<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2011 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLES2Texture.h"
#include "OgreGLES2PixelFormat.h"
#include "OgreGLES2RenderSystem.h"
#include "OgreGLES2HardwarePixelBuffer.h"
#include "OgreRoot.h"

namespace Ogre {
    static inline void doImageIO(const String &name, const String &group,
                                 const String &ext,
                                 vector<Image>::type &images,
                                 Resource *r)
    {
        size_t imgIdx = images.size();
        images.push_back(Image());

        DataStreamPtr dstream =
            ResourceGroupManager::getSingleton().openResource(
                name, group, true, r);

        images[imgIdx].load(dstream, ext);
    }

    GLES2Texture::GLES2Texture(ResourceManager* creator, const String& name,
                             ResourceHandle handle, const String& group, bool isManual,
                             ManualResourceLoader* loader, GLES2Support& support)
        : Texture(creator, name, handle, group, isManual, loader),
          mTextureID(0), mGLSupport(support)
    {
    }

    GLES2Texture::~GLES2Texture()
    {
        // have to call this here rather than in Resource destructor
        // since calling virtual methods in base destructors causes crash
        if (isLoaded())
        {
            unload();
        }
        else
        {
            freeInternalResources();
        }
    }

    GLenum GLES2Texture::getGLES2TextureTarget(void) const
    {
        switch(mTextureType)
        {
            case TEX_TYPE_1D:
            case TEX_TYPE_2D:
                return GL_TEXTURE_2D;
            case TEX_TYPE_CUBE_MAP:
                return GL_TEXTURE_CUBE_MAP;
            default:
                return 0;
        };
    }

    // Creation / loading methods
    void GLES2Texture::createInternalResourcesImpl(void)
    {
		// Convert to nearest power-of-two size if required
        mWidth = GLES2PixelUtil::optionalPO2(mWidth);
        mHeight = GLES2PixelUtil::optionalPO2(mHeight);
        mDepth = GLES2PixelUtil::optionalPO2(mDepth);

		// Adjust format if required
        mFormat = TextureManager::getSingleton().getNativeFormat(mTextureType, mFormat, mUsage);

		// Check requested number of mipmaps
        size_t maxMips = GLES2PixelUtil::getMaxMipmaps(mWidth, mHeight, mDepth, mFormat);

        if(PixelUtil::isCompressed(mFormat) && (mNumMipmaps == 0))
            mNumRequestedMipmaps = 0;

        mNumMipmaps = mNumRequestedMipmaps;
        if (mNumMipmaps > maxMips)
            mNumMipmaps = maxMips;

		// Generate texture name
        glGenTextures(1, &mTextureID);
        GL_CHECK_ERROR;

		// Set texture type
        glBindTexture(getGLES2TextureTarget(), mTextureID);
        GL_CHECK_ERROR;

#if GL_APPLE_texture_max_level
        glTexParameteri( getGLES2TextureTarget(), GL_TEXTURE_MAX_LEVEL_APPLE, mNumMipmaps );
#endif

        // Set some misc default parameters, these can of course be changed later
        glTexParameteri(getGLES2TextureTarget(),
                        GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        GL_CHECK_ERROR;
        glTexParameteri(getGLES2TextureTarget(),
                        GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        GL_CHECK_ERROR;
        glTexParameteri(getGLES2TextureTarget(),
                        GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        GL_CHECK_ERROR;
        glTexParameteri(getGLES2TextureTarget(),
                        GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        GL_CHECK_ERROR;

		// If we can do automip generation and the user desires this, do so
        mMipmapsHardwareGenerated =
            Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_AUTOMIPMAP) && !PixelUtil::isCompressed(mFormat);

        if ((mUsage & TU_AUTOMIPMAP) &&
            mNumRequestedMipmaps && mMipmapsHardwareGenerated)
        {
            glGenerateMipmap(getGLES2TextureTarget());
            GL_CHECK_ERROR;
        }

        // Allocate internal buffer so that glTexSubImageXD can be used
        // Internal format
        GLenum format = GLES2PixelUtil::getClosestGLInternalFormat(mFormat, mHwGamma);
        GLenum datatype = GLES2PixelUtil::getGLOriginDataType(mFormat);
        size_t width = mWidth;
        size_t height = mHeight;
        size_t depth = mDepth;

        if (PixelUtil::isCompressed(mFormat))
        {
            // Compressed formats
            size_t size = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);

            // Provide temporary buffer filled with zeroes as glCompressedTexImageXD does not
            // accept a 0 pointer like normal glTexImageXD
            // Run through this process for every mipmap to pregenerate mipmap pyramid

            uint8* tmpdata = OGRE_NEW_FIX_FOR_WIN32 uint8[size];
            memset(tmpdata, 0, size);
            for (size_t mip = 0; mip <= mNumMipmaps; mip++)
            {
                size = PixelUtil::getMemorySize(width, height, depth, mFormat);

				switch(mTextureType)
				{
					case TEX_TYPE_1D:
					case TEX_TYPE_2D:
                        glCompressedTexImage2D(GL_TEXTURE_2D,
                                               mip,
                                               format,
                                               width, height,
                                               0,
                                               size,
                                               tmpdata);
                        GL_CHECK_ERROR;
                        break;
					case TEX_TYPE_CUBE_MAP:
						for(int face = 0; face < 6; face++) {
							glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, format,
								width, height, 0,
								size, tmpdata);
                            GL_CHECK_ERROR;
						}
						break;
					case TEX_TYPE_3D:
                    default:
                        break;
                };
//                LogManager::getSingleton().logMessage("GLES2Texture::create - Mip: " + StringConverter::toString(mip) +
//                                                      " Width: " + StringConverter::toString(width) +
//                                                      " Height: " + StringConverter::toString(height) +
//                                                      " Internal Format: " + StringConverter::toString(format)
//                                                      );

                if(width > 1)
                {
                    width = width / 2;
                }
                if(height > 1)
                {
                    height = height / 2;
                }
                if(depth > 1)
                {
                    depth = depth / 2;
                }
            }
            OGRE_DELETE [] tmpdata;
        }
        else
        {
            // Run through this process to pregenerate mipmap pyramid
            for(size_t mip = 0; mip <= mNumMipmaps; mip++)
            {
				// Normal formats
				switch(mTextureType)
				{
					case TEX_TYPE_1D:
					case TEX_TYPE_2D:
                        glTexImage2D(GL_TEXTURE_2D,
                                     mip,
                                     format,
                                     width, height,
                                     0,
                                     format,
                                     datatype, 0);
                        GL_CHECK_ERROR;
                        break;
					case TEX_TYPE_CUBE_MAP:
						for(int face = 0; face < 6; face++) {
							glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, format,
								width, height, 0,
								format, datatype, 0);
						}
						break;
					case TEX_TYPE_3D:
                    default:
                        break;
                };
//                LogManager::getSingleton().logMessage("GLES2Texture::create - Mip: " + StringConverter::toString(mip) +
//                                                      " Width: " + StringConverter::toString(width) +
//                                                      " Height: " + StringConverter::toString(height) +
//                                                      " Internal Format: " + StringConverter::toString(format)
//                                                      );

                if (width > 1)
                {
                    width = width / 2;
                }
                if (height > 1)
                {
                    height = height / 2;
                }
            }
        }

        _createSurfaceList();

        // Get final internal format
        mFormat = getBuffer(0,0)->getFormat();
    }

    void GLES2Texture::createRenderTexture(void)
    {
        // Create the GL texture
        // This already does everything necessary
        createInternalResources();
    }

    void GLES2Texture::prepareImpl()
    {
        if (mUsage & TU_RENDERTARGET) return;

        String baseName, ext;
        size_t pos = mName.find_last_of(".");
        baseName = mName.substr(0, pos);

        if (pos != String::npos)
        {
            ext = mName.substr(pos+1);
        }

        LoadedImages loadedImages = LoadedImages(OGRE_NEW_FIX_FOR_WIN32 vector<Image>::type());

        if (mTextureType == TEX_TYPE_1D || mTextureType == TEX_TYPE_2D)
        {
            doImageIO(mName, mGroup, ext, *loadedImages, this);

            // If this is a volumetric texture set the texture type flag accordingly.
            // If this is a cube map, set the texture type flag accordingly.
            if ((*loadedImages)[0].hasFlag(IF_CUBEMAP))
                mTextureType = TEX_TYPE_CUBE_MAP;

			// If PVRTC and 0 custom mipmap disable auto mip generation and disable software mipmap creation
            PixelFormat imageFormat = (*loadedImages)[0].getFormat();
			if (imageFormat == PF_PVRTC_RGB2 || imageFormat == PF_PVRTC_RGBA2 ||
                imageFormat == PF_PVRTC_RGB4 || imageFormat == PF_PVRTC_RGBA4)
			{
                size_t imageMips = (*loadedImages)[0].getNumMipmaps();
                if (imageMips == 0)
                {
                    mNumMipmaps = mNumRequestedMipmaps = imageMips;
                    // Disable flag for auto mip generation
                    mUsage &= ~TU_AUTOMIPMAP;
                }
			}
        }
        else if (mTextureType == TEX_TYPE_CUBE_MAP)
        {
            if(getSourceFileType() == "dds")
            {
                // XX HACK there should be a better way to specify whether
                // all faces are in the same file or not
                doImageIO(mName, mGroup, ext, *loadedImages, this);
            }
            else
            {
                vector<Image>::type images(6);
                ConstImagePtrList imagePtrs;
                static const String suffixes[6] = {"_rt", "_lf", "_up", "_dn", "_fr", "_bk"};

                for(size_t i = 0; i < 6; i++)
                {
                    String fullName = baseName + suffixes[i];
                    if (!ext.empty())
                        fullName = fullName + "." + ext;
                    // find & load resource data intro stream to allow resource
                    // group changes if required
                    doImageIO(fullName, mGroup, ext, *loadedImages, this);
                }
            }
        }
        else
        {
            OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
                        "**** Unknown texture type ****",
                        "GLES2Texture::prepare");
        }

        mLoadedImages = loadedImages;
    }

    void GLES2Texture::unprepareImpl()
    {
        mLoadedImages.setNull();
    }

    void GLES2Texture::loadImpl()
    {
        if (mUsage & TU_RENDERTARGET)
        {
            createRenderTexture();
            return;
        }

        // Now the only copy is on the stack and will be cleaned in case of
        // exceptions being thrown from _loadImages
        LoadedImages loadedImages = mLoadedImages;
        mLoadedImages.setNull();

        // Call internal _loadImages, not loadImage since that's external and
        // will determine load status etc again
        ConstImagePtrList imagePtrs;

        for (size_t i = 0; i < loadedImages->size(); ++i)
        {
            imagePtrs.push_back(&(*loadedImages)[i]);
        }

        _loadImages(imagePtrs);
    }

    void GLES2Texture::freeInternalResourcesImpl()
    {
        mSurfaceList.clear();
        glDeleteTextures(1, &mTextureID);
        GL_CHECK_ERROR;
    }

    void GLES2Texture::_createSurfaceList()
    {
        mSurfaceList.clear();

        // For all faces and mipmaps, store surfaces as HardwarePixelBufferSharedPtr
        bool wantGeneratedMips = (mUsage & TU_AUTOMIPMAP)!=0;

        // Do mipmapping in software? (uses GLU) For some cards, this is still needed. Of course,
        // only when mipmap generation is desired.
        bool doSoftware = wantGeneratedMips && !mMipmapsHardwareGenerated && getNumMipmaps();

        for (size_t face = 0; face < getNumFaces(); face++)
        {
			size_t width = mWidth;
			size_t height = mHeight;

            for (size_t mip = 0; mip <= getNumMipmaps(); mip++)
            {
                GLES2HardwarePixelBuffer *buf = OGRE_NEW GLES2TextureBuffer(mName,
                                                                            getGLES2TextureTarget(),
                                                                            mTextureID,
                                                                            width, height,
                                                                            GLES2PixelUtil::getClosestGLInternalFormat(mFormat, mHwGamma),
                                                                            GLES2PixelUtil::getGLOriginDataType(mFormat),
                                                                            face,
                                                                            mip,
                                                                            static_cast<HardwareBuffer::Usage>(mUsage),
                                                                            doSoftware && mip==0, mHwGamma, mFSAA);

                mSurfaceList.push_back(HardwarePixelBufferSharedPtr(buf));

                // Check for error
                if (buf->getWidth() == 0 ||
                    buf->getHeight() == 0 ||
                    buf->getDepth() == 0)
                {
                    OGRE_EXCEPT(
                        Exception::ERR_RENDERINGAPI_ERROR,
                        "Zero sized texture surface on texture "+getName()+
                            " face "+StringConverter::toString(face)+
                            " mipmap "+StringConverter::toString(mip)+
                            ". The GL driver probably refused to create the texture.",
                            "GLES2Texture::_createSurfaceList");
                }
            }
        }
    }

    HardwarePixelBufferSharedPtr GLES2Texture::getBuffer(size_t face, size_t mipmap)
    {
        if (face >= getNumFaces())
        {
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "Face index out of range",
                        "GLES2Texture::getBuffer");
        }

        if (mipmap > mNumMipmaps)
        {
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "Mipmap index out of range",
                        "GLES2Texture::getBuffer");
        }

        unsigned int idx = face * (mNumMipmaps + 1) + mipmap;
        assert(idx < mSurfaceList.size());
        return mSurfaceList[idx];
    }
}
<commit_msg>GLES2: Resolve some GL errors by excluding cube maps from getting auto generated mipmaps<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2011 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLES2Texture.h"
#include "OgreGLES2PixelFormat.h"
#include "OgreGLES2RenderSystem.h"
#include "OgreGLES2HardwarePixelBuffer.h"
#include "OgreRoot.h"

namespace Ogre {
    static inline void doImageIO(const String &name, const String &group,
                                 const String &ext,
                                 vector<Image>::type &images,
                                 Resource *r)
    {
        size_t imgIdx = images.size();
        images.push_back(Image());

        DataStreamPtr dstream =
            ResourceGroupManager::getSingleton().openResource(
                name, group, true, r);

        images[imgIdx].load(dstream, ext);
    }

    GLES2Texture::GLES2Texture(ResourceManager* creator, const String& name,
                             ResourceHandle handle, const String& group, bool isManual,
                             ManualResourceLoader* loader, GLES2Support& support)
        : Texture(creator, name, handle, group, isManual, loader),
          mTextureID(0), mGLSupport(support)
    {
    }

    GLES2Texture::~GLES2Texture()
    {
        // have to call this here rather than in Resource destructor
        // since calling virtual methods in base destructors causes crash
        if (isLoaded())
        {
            unload();
        }
        else
        {
            freeInternalResources();
        }
    }

    GLenum GLES2Texture::getGLES2TextureTarget(void) const
    {
        switch(mTextureType)
        {
            case TEX_TYPE_1D:
            case TEX_TYPE_2D:
                return GL_TEXTURE_2D;
            case TEX_TYPE_CUBE_MAP:
                return GL_TEXTURE_CUBE_MAP;
            default:
                return 0;
        };
    }

    // Creation / loading methods
    void GLES2Texture::createInternalResourcesImpl(void)
    {
		// Convert to nearest power-of-two size if required
        mWidth = GLES2PixelUtil::optionalPO2(mWidth);
        mHeight = GLES2PixelUtil::optionalPO2(mHeight);
        mDepth = GLES2PixelUtil::optionalPO2(mDepth);

		// Adjust format if required
        mFormat = TextureManager::getSingleton().getNativeFormat(mTextureType, mFormat, mUsage);

		// Check requested number of mipmaps
        size_t maxMips = GLES2PixelUtil::getMaxMipmaps(mWidth, mHeight, mDepth, mFormat);

        if(PixelUtil::isCompressed(mFormat) && (mNumMipmaps == 0))
            mNumRequestedMipmaps = 0;

        mNumMipmaps = mNumRequestedMipmaps;
        if (mNumMipmaps > maxMips)
            mNumMipmaps = maxMips;

		// Generate texture name
        glGenTextures(1, &mTextureID);
        GL_CHECK_ERROR;

		// Set texture type
        glBindTexture(getGLES2TextureTarget(), mTextureID);
        GL_CHECK_ERROR;

#if GL_APPLE_texture_max_level
        glTexParameteri( getGLES2TextureTarget(), GL_TEXTURE_MAX_LEVEL_APPLE, mNumMipmaps );
#endif

        // Set some misc default parameters, these can of course be changed later
        glTexParameteri(getGLES2TextureTarget(),
                        GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        GL_CHECK_ERROR;
        glTexParameteri(getGLES2TextureTarget(),
                        GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        GL_CHECK_ERROR;
        glTexParameteri(getGLES2TextureTarget(),
                        GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        GL_CHECK_ERROR;
        glTexParameteri(getGLES2TextureTarget(),
                        GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        GL_CHECK_ERROR;

		// If we can do automip generation and the user desires this, do so
        mMipmapsHardwareGenerated =
            Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_AUTOMIPMAP) && !PixelUtil::isCompressed(mFormat);

        if ((mUsage & TU_AUTOMIPMAP) &&
            mNumRequestedMipmaps && mMipmapsHardwareGenerated &&
            (mTextureType != TEX_TYPE_CUBE_MAP))
        {
            glGenerateMipmap(getGLES2TextureTarget());
            GL_CHECK_ERROR;
        }

        // Allocate internal buffer so that glTexSubImageXD can be used
        // Internal format
        GLenum format = GLES2PixelUtil::getClosestGLInternalFormat(mFormat, mHwGamma);
        GLenum datatype = GLES2PixelUtil::getGLOriginDataType(mFormat);
        size_t width = mWidth;
        size_t height = mHeight;
        size_t depth = mDepth;

        if (PixelUtil::isCompressed(mFormat))
        {
            // Compressed formats
            size_t size = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);

            // Provide temporary buffer filled with zeroes as glCompressedTexImageXD does not
            // accept a 0 pointer like normal glTexImageXD
            // Run through this process for every mipmap to pregenerate mipmap pyramid

            uint8* tmpdata = OGRE_NEW_FIX_FOR_WIN32 uint8[size];
            memset(tmpdata, 0, size);
            for (size_t mip = 0; mip <= mNumMipmaps; mip++)
            {
                size = PixelUtil::getMemorySize(width, height, depth, mFormat);

				switch(mTextureType)
				{
					case TEX_TYPE_1D:
					case TEX_TYPE_2D:
                        glCompressedTexImage2D(GL_TEXTURE_2D,
                                               mip,
                                               format,
                                               width, height,
                                               0,
                                               size,
                                               tmpdata);
                        GL_CHECK_ERROR;
                        break;
					case TEX_TYPE_CUBE_MAP:
						for(int face = 0; face < 6; face++) {
							glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, format,
								width, height, 0,
								size, tmpdata);
                            GL_CHECK_ERROR;
						}
						break;
					case TEX_TYPE_3D:
                    default:
                        break;
                };
//                LogManager::getSingleton().logMessage("GLES2Texture::create - Mip: " + StringConverter::toString(mip) +
//                                                      " Width: " + StringConverter::toString(width) +
//                                                      " Height: " + StringConverter::toString(height) +
//                                                      " Internal Format: " + StringConverter::toString(format)
//                                                      );

                if(width > 1)
                {
                    width = width / 2;
                }
                if(height > 1)
                {
                    height = height / 2;
                }
                if(depth > 1)
                {
                    depth = depth / 2;
                }
            }
            OGRE_DELETE [] tmpdata;
        }
        else
        {
            // Run through this process to pregenerate mipmap pyramid
            for(size_t mip = 0; mip <= mNumMipmaps; mip++)
            {
				// Normal formats
				switch(mTextureType)
				{
					case TEX_TYPE_1D:
					case TEX_TYPE_2D:
                        glTexImage2D(GL_TEXTURE_2D,
                                     mip,
                                     format,
                                     width, height,
                                     0,
                                     format,
                                     datatype, 0);
                        GL_CHECK_ERROR;
                        break;
					case TEX_TYPE_CUBE_MAP:
						for(int face = 0; face < 6; face++) {
							glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, format,
								width, height, 0,
								format, datatype, 0);
						}
						break;
					case TEX_TYPE_3D:
                    default:
                        break;
                };
//                LogManager::getSingleton().logMessage("GLES2Texture::create - Mip: " + StringConverter::toString(mip) +
//                                                      " Width: " + StringConverter::toString(width) +
//                                                      " Height: " + StringConverter::toString(height) +
//                                                      " Internal Format: " + StringConverter::toString(format)
//                                                      );

                if (width > 1)
                {
                    width = width / 2;
                }
                if (height > 1)
                {
                    height = height / 2;
                }
            }
        }

        _createSurfaceList();

        // Get final internal format
        mFormat = getBuffer(0,0)->getFormat();
    }

    void GLES2Texture::createRenderTexture(void)
    {
        // Create the GL texture
        // This already does everything necessary
        createInternalResources();
    }

    void GLES2Texture::prepareImpl()
    {
        if (mUsage & TU_RENDERTARGET) return;

        String baseName, ext;
        size_t pos = mName.find_last_of(".");
        baseName = mName.substr(0, pos);

        if (pos != String::npos)
        {
            ext = mName.substr(pos+1);
        }

        LoadedImages loadedImages = LoadedImages(OGRE_NEW_FIX_FOR_WIN32 vector<Image>::type());

        if (mTextureType == TEX_TYPE_1D || mTextureType == TEX_TYPE_2D)
        {
            doImageIO(mName, mGroup, ext, *loadedImages, this);

            // If this is a volumetric texture set the texture type flag accordingly.
            // If this is a cube map, set the texture type flag accordingly.
            if ((*loadedImages)[0].hasFlag(IF_CUBEMAP))
                mTextureType = TEX_TYPE_CUBE_MAP;

			// If PVRTC and 0 custom mipmap disable auto mip generation and disable software mipmap creation
            PixelFormat imageFormat = (*loadedImages)[0].getFormat();
			if (imageFormat == PF_PVRTC_RGB2 || imageFormat == PF_PVRTC_RGBA2 ||
                imageFormat == PF_PVRTC_RGB4 || imageFormat == PF_PVRTC_RGBA4)
			{
                size_t imageMips = (*loadedImages)[0].getNumMipmaps();
                if (imageMips == 0)
                {
                    mNumMipmaps = mNumRequestedMipmaps = imageMips;
                    // Disable flag for auto mip generation
                    mUsage &= ~TU_AUTOMIPMAP;
                }
			}
        }
        else if (mTextureType == TEX_TYPE_CUBE_MAP)
        {
            if(getSourceFileType() == "dds")
            {
                // XX HACK there should be a better way to specify whether
                // all faces are in the same file or not
                doImageIO(mName, mGroup, ext, *loadedImages, this);
            }
            else
            {
                vector<Image>::type images(6);
                ConstImagePtrList imagePtrs;
                static const String suffixes[6] = {"_rt", "_lf", "_up", "_dn", "_fr", "_bk"};

                for(size_t i = 0; i < 6; i++)
                {
                    String fullName = baseName + suffixes[i];
                    if (!ext.empty())
                        fullName = fullName + "." + ext;
                    // find & load resource data intro stream to allow resource
                    // group changes if required
                    doImageIO(fullName, mGroup, ext, *loadedImages, this);
                }
            }
        }
        else
        {
            OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
                        "**** Unknown texture type ****",
                        "GLES2Texture::prepare");
        }

        mLoadedImages = loadedImages;
    }

    void GLES2Texture::unprepareImpl()
    {
        mLoadedImages.setNull();
    }

    void GLES2Texture::loadImpl()
    {
        if (mUsage & TU_RENDERTARGET)
        {
            createRenderTexture();
            return;
        }

        // Now the only copy is on the stack and will be cleaned in case of
        // exceptions being thrown from _loadImages
        LoadedImages loadedImages = mLoadedImages;
        mLoadedImages.setNull();

        // Call internal _loadImages, not loadImage since that's external and
        // will determine load status etc again
        ConstImagePtrList imagePtrs;

        for (size_t i = 0; i < loadedImages->size(); ++i)
        {
            imagePtrs.push_back(&(*loadedImages)[i]);
        }

        _loadImages(imagePtrs);
    }

    void GLES2Texture::freeInternalResourcesImpl()
    {
        mSurfaceList.clear();
        glDeleteTextures(1, &mTextureID);
        GL_CHECK_ERROR;
    }

    void GLES2Texture::_createSurfaceList()
    {
        mSurfaceList.clear();

        // For all faces and mipmaps, store surfaces as HardwarePixelBufferSharedPtr
        bool wantGeneratedMips = (mUsage & TU_AUTOMIPMAP)!=0;

        // Do mipmapping in software? (uses GLU) For some cards, this is still needed. Of course,
        // only when mipmap generation is desired.
        bool doSoftware = wantGeneratedMips && !mMipmapsHardwareGenerated && getNumMipmaps();

        for (size_t face = 0; face < getNumFaces(); face++)
        {
			size_t width = mWidth;
			size_t height = mHeight;

            for (size_t mip = 0; mip <= getNumMipmaps(); mip++)
            {
                GLES2HardwarePixelBuffer *buf = OGRE_NEW GLES2TextureBuffer(mName,
                                                                            getGLES2TextureTarget(),
                                                                            mTextureID,
                                                                            width, height,
                                                                            GLES2PixelUtil::getClosestGLInternalFormat(mFormat, mHwGamma),
                                                                            GLES2PixelUtil::getGLOriginDataType(mFormat),
                                                                            face,
                                                                            mip,
                                                                            static_cast<HardwareBuffer::Usage>(mUsage),
                                                                            doSoftware && mip==0, mHwGamma, mFSAA);

                mSurfaceList.push_back(HardwarePixelBufferSharedPtr(buf));

                // Check for error
                if (buf->getWidth() == 0 ||
                    buf->getHeight() == 0 ||
                    buf->getDepth() == 0)
                {
                    OGRE_EXCEPT(
                        Exception::ERR_RENDERINGAPI_ERROR,
                        "Zero sized texture surface on texture "+getName()+
                            " face "+StringConverter::toString(face)+
                            " mipmap "+StringConverter::toString(mip)+
                            ". The GL driver probably refused to create the texture.",
                            "GLES2Texture::_createSurfaceList");
                }
            }
        }
    }

    HardwarePixelBufferSharedPtr GLES2Texture::getBuffer(size_t face, size_t mipmap)
    {
        if (face >= getNumFaces())
        {
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "Face index out of range",
                        "GLES2Texture::getBuffer");
        }

        if (mipmap > mNumMipmaps)
        {
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "Mipmap index out of range",
                        "GLES2Texture::getBuffer");
        }

        unsigned int idx = face * (mNumMipmaps + 1) + mipmap;
        assert(idx < mSurfaceList.size());
        return mSurfaceList[idx];
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Client.hxx"
#include "net/RConnectSocket.hxx"
#include "net/SendMessage.hxx"
#include "net/ScmRightsBuilder.hxx"
#include "net/MsgHdr.hxx"
#include "io/Iovec.hxx"
#include "system/Error.hxx"
#include "util/ByteOrder.hxx"

#include <cstring>

inline
BengControlClient::BengControlClient(UniqueSocketDescriptor _socket) noexcept
	:socket(std::move(_socket)) {}

BengControlClient::BengControlClient(const char *host_and_port)
	:BengControlClient(ResolveConnectDatagramSocket(host_and_port,
							5478)) {}

static constexpr size_t
PaddingSize(size_t size) noexcept
{
	return (3 - ((size - 1) & 0x3));
}

void
BengControlClient::Send(BengProxy::ControlCommand cmd,
			std::span<const std::byte> payload,
			std::span<const FileDescriptor> fds) const
{
	static constexpr uint32_t magic = ToBE32(BengProxy::control_magic);
	const BengProxy::ControlHeader header{ToBE16(payload.size()), ToBE16(uint16_t(cmd))};

	static constexpr uint8_t padding[3] = {0, 0, 0};

	const struct iovec v[] = {
		MakeIovecT(magic),
		MakeIovecT(header),
		MakeIovec(payload),
		MakeIovec(std::span{padding, PaddingSize(payload.size())}),
	};

	MessageHeader msg{std::span{v}};

	ScmRightsBuilder<1> b(msg);
	for (const auto &i : fds)
		b.push_back(i.Get());
	b.Finish(msg);

	SendMessage(socket, msg, 0);
}

std::pair<BengProxy::ControlCommand, std::string>
BengControlClient::Receive() const
{
	int result = socket.WaitReadable(10000);
	if (result < 0)
		throw MakeErrno("poll() failed");

	if (result == 0)
		throw std::runtime_error("Timeout");

	BengProxy::ControlHeader header;
	char payload[4096];

	struct iovec v[] = {
		MakeIovecT(header),
		MakeIovecT(payload),
	};

	auto msg = MakeMsgHdr(v);

	auto nbytes = recvmsg(socket.Get(), &msg, 0);
	if (nbytes < 0)
		throw MakeErrno("recvmsg() failed");

	if (size_t(nbytes) < sizeof(header))
		throw std::runtime_error("Short receive");

	size_t payload_length = FromBE16(header.length);
	if (sizeof(header) + payload_length > size_t(nbytes))
		throw std::runtime_error("Truncated datagram");

	return std::make_pair(BengProxy::ControlCommand(FromBE16(header.command)),
			      std::string(payload, payload_length));
}

std::string
BengControlClient::MakeTcacheInvalidate(TranslationCommand cmd,
					std::span<const std::byte> payload) noexcept
{
	TranslationHeader h;
	h.length = ToBE16(payload.size());
	h.command = TranslationCommand(ToBE16(uint16_t(cmd)));

	std::string result;
	result.append((const char *)&h, sizeof(h));
	if (!payload.empty()) {
		result.append((const char *)payload.data(), payload.size());
		result.append(PaddingSize(payload.size()), '\0');
	}

	return result;
}

std::string
BengControlClient::MakeTcacheInvalidate(TranslationCommand cmd,
					const char *value) noexcept
{
	const std::span value_span{value, strlen(value) + 1};
	return MakeTcacheInvalidate(cmd, std::as_bytes(value_span));
}
<commit_msg>control/Client: omit the null terminator<commit_after>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Client.hxx"
#include "net/RConnectSocket.hxx"
#include "net/SendMessage.hxx"
#include "net/ScmRightsBuilder.hxx"
#include "net/MsgHdr.hxx"
#include "io/Iovec.hxx"
#include "system/Error.hxx"
#include "util/ByteOrder.hxx"

#include <cstring>

inline
BengControlClient::BengControlClient(UniqueSocketDescriptor _socket) noexcept
	:socket(std::move(_socket)) {}

BengControlClient::BengControlClient(const char *host_and_port)
	:BengControlClient(ResolveConnectDatagramSocket(host_and_port,
							5478)) {}

static constexpr size_t
PaddingSize(size_t size) noexcept
{
	return (3 - ((size - 1) & 0x3));
}

void
BengControlClient::Send(BengProxy::ControlCommand cmd,
			std::span<const std::byte> payload,
			std::span<const FileDescriptor> fds) const
{
	static constexpr uint32_t magic = ToBE32(BengProxy::control_magic);
	const BengProxy::ControlHeader header{ToBE16(payload.size()), ToBE16(uint16_t(cmd))};

	static constexpr uint8_t padding[3] = {0, 0, 0};

	const struct iovec v[] = {
		MakeIovecT(magic),
		MakeIovecT(header),
		MakeIovec(payload),
		MakeIovec(std::span{padding, PaddingSize(payload.size())}),
	};

	MessageHeader msg{std::span{v}};

	ScmRightsBuilder<1> b(msg);
	for (const auto &i : fds)
		b.push_back(i.Get());
	b.Finish(msg);

	SendMessage(socket, msg, 0);
}

std::pair<BengProxy::ControlCommand, std::string>
BengControlClient::Receive() const
{
	int result = socket.WaitReadable(10000);
	if (result < 0)
		throw MakeErrno("poll() failed");

	if (result == 0)
		throw std::runtime_error("Timeout");

	BengProxy::ControlHeader header;
	char payload[4096];

	struct iovec v[] = {
		MakeIovecT(header),
		MakeIovecT(payload),
	};

	auto msg = MakeMsgHdr(v);

	auto nbytes = recvmsg(socket.Get(), &msg, 0);
	if (nbytes < 0)
		throw MakeErrno("recvmsg() failed");

	if (size_t(nbytes) < sizeof(header))
		throw std::runtime_error("Short receive");

	size_t payload_length = FromBE16(header.length);
	if (sizeof(header) + payload_length > size_t(nbytes))
		throw std::runtime_error("Truncated datagram");

	return std::make_pair(BengProxy::ControlCommand(FromBE16(header.command)),
			      std::string(payload, payload_length));
}

std::string
BengControlClient::MakeTcacheInvalidate(TranslationCommand cmd,
					std::span<const std::byte> payload) noexcept
{
	TranslationHeader h;
	h.length = ToBE16(payload.size());
	h.command = TranslationCommand(ToBE16(uint16_t(cmd)));

	std::string result;
	result.append((const char *)&h, sizeof(h));
	if (!payload.empty()) {
		result.append((const char *)payload.data(), payload.size());
		result.append(PaddingSize(payload.size()), '\0');
	}

	return result;
}

std::string
BengControlClient::MakeTcacheInvalidate(TranslationCommand cmd,
					const char *value) noexcept
{
	const std::span value_span{value, strlen(value)};
	return MakeTcacheInvalidate(cmd, std::as_bytes(value_span));
}
<|endoftext|>


<commit_before>#line 2 "togo/tool_build/interface/command_list.ipp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

namespace togo {
namespace tool_build {

static void print_package(
	PackageCompiler const& pkg,
	bool const list_resources
) {
	auto const pkg_name = package_compiler::name(pkg);
	TOGO_LOGF(
		"[%08x] %.*s\n",
		package_compiler::name_hash(pkg),
		pkg_name.size, pkg_name.data
	);
	if (!list_resources) {
		return;
	} else if (array::empty(package_compiler::manifest(pkg))) {
		TOGO_LOG("  no resources\n\n");
		return;
	}
	for (auto const& metadata : package_compiler::manifest(pkg)) {
		TOGO_LOGF(
			"  %c [%08x %016lx] %.*s\n",
			metadata.last_compiled == 0 ? ' ' : 'C',
			metadata.type, metadata.name_hash,
			string::size(metadata.path),
			fixed_array::begin(metadata.path)
		);
	}
	TOGO_LOG("\n");
}

bool interface::command_list(
	Interface const& interface,
	bool const list_resources,
	StringRef const* const package_names,
	unsigned const num_package_names
) {
	TOGO_ASSERTE(package_names || num_package_names == 0);
	auto const& packages = compiler_manager::packages(interface._manager);
	if (num_package_names > 0) {
		PackageCompiler* pkg;
		for (unsigned i = 0; i < num_package_names; ++i) {
			auto const& pkg_name = package_names[i];
			pkg = compiler_manager::get_package(
				const_cast<CompilerManager&>(interface._manager),
				resource::hash_package_name(pkg_name)
			);
			if (pkg) {
				print_package(*pkg, true);
			} else {
				TOGO_LOGF(
					"package not found: '%.*s'\n",
					pkg_name.size, pkg_name.data
				);
			}
		}
	} else if (array::any(packages)) {
		for (auto const* pkg : packages) {
			print_package(*pkg, list_resources);
		}
	} else {
		TOGO_LOG("no packages\n");
	}
	return true;
}

bool interface::command_list(
	Interface const& interface,
	KVS const& k_command_options,
	KVS const& k_command
) {
	bool opt_resources = false;
	for (KVS const& k_opt : k_command_options) {
		switch (kvs::name_hash(k_opt)) {
		case "-r"_kvs_name:
			if (!kvs::is_boolean(k_opt)) {
				TOGO_LOG("error: -r: expected boolean value\n");
				return false;
			}
			opt_resources = kvs::boolean(k_opt);
			break;

		default:
			TOGO_LOGF(
				"error: option '%.*s' not recognized\n",
				kvs::name_size(k_opt), kvs::name(k_opt)
			);
			return false;
		}
	}
	if (opt_resources) {
		if (kvs::any(k_command)) {
			TOGO_LOG("NB: takes no arguments with -r\n");
		}
		return interface::command_list(interface, true, nullptr, 0);
	} else {
		FixedArray<StringRef, 32> package_names{};
		for (KVS const& k_pkg_name : k_command) {
			if (!kvs::is_string(k_pkg_name) || kvs::string_size(k_pkg_name) == 0) {
				TOGO_LOG("error: expected non-empty string argument\n");
				return false;
			}
			fixed_array::push_back(package_names, kvs::string_ref(k_pkg_name));
		}
		return interface::command_list(
			interface,
			false,
			fixed_array::begin(package_names),
			fixed_array::size(package_names)
		);
	}
}

} // namespace tool_build
} // namespace togo
<commit_msg>tool_build/interface/command_list: output tidy.<commit_after>#line 2 "togo/tool_build/interface/command_list.ipp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

namespace togo {
namespace tool_build {

static void print_package(
	PackageCompiler const& pkg,
	bool const list_resources
) {
	auto const pkg_name = package_compiler::name(pkg);
	TOGO_LOGF(
		"[%08x] %.*s\n",
		package_compiler::name_hash(pkg),
		pkg_name.size, pkg_name.data
	);
	if (!list_resources) {
		return;
	} else if (array::empty(package_compiler::manifest(pkg))) {
		TOGO_LOG("  no resources\n");
		return;
	}
	for (auto const& metadata : package_compiler::manifest(pkg)) {
		TOGO_LOGF(
			"  %c [%08x %016lx] %.*s\n",
			metadata.last_compiled == 0 ? ' ' : 'C',
			metadata.type, metadata.name_hash,
			string::size(metadata.path),
			fixed_array::begin(metadata.path)
		);
	}
}

bool interface::command_list(
	Interface const& interface,
	bool const list_resources,
	StringRef const* const package_names,
	unsigned const num_package_names
) {
	TOGO_ASSERTE(package_names || num_package_names == 0);
	auto const& packages = compiler_manager::packages(interface._manager);
	if (num_package_names > 0) {
		PackageCompiler* pkg;
		for (unsigned i = 0; i < num_package_names; ++i) {
			auto const& pkg_name = package_names[i];
			pkg = compiler_manager::get_package(
				const_cast<CompilerManager&>(interface._manager),
				resource::hash_package_name(pkg_name)
			);
			if (pkg) {
				print_package(*pkg, true);
				if (list_resources && i + 1 < num_package_names) {
					TOGO_LOG("\n");
				}
			} else {
				TOGO_LOGF(
					"package not found: '%.*s'\n",
					pkg_name.size, pkg_name.data
				);
			}
		}
	} else if (array::any(packages)) {
		for (unsigned i = 0; i < array::size(packages); ++i) {
			auto const* pkg = packages[i];
			print_package(*pkg, list_resources);
			if (list_resources && i + 1 < array::size(packages)) {
				TOGO_LOG("\n");
			}
		}
	} else {
		TOGO_LOG("no packages\n");
	}
	return true;
}

bool interface::command_list(
	Interface const& interface,
	KVS const& k_command_options,
	KVS const& k_command
) {
	bool opt_resources = false;
	for (KVS const& k_opt : k_command_options) {
		switch (kvs::name_hash(k_opt)) {
		case "-r"_kvs_name:
			if (!kvs::is_boolean(k_opt)) {
				TOGO_LOG("error: -r: expected boolean value\n");
				return false;
			}
			opt_resources = kvs::boolean(k_opt);
			break;

		default:
			TOGO_LOGF(
				"error: option '%.*s' not recognized\n",
				kvs::name_size(k_opt), kvs::name(k_opt)
			);
			return false;
		}
	}
	if (opt_resources) {
		if (kvs::any(k_command)) {
			TOGO_LOG("NB: takes no arguments with -r\n");
		}
		return interface::command_list(interface, true, nullptr, 0);
	} else {
		FixedArray<StringRef, 32> package_names{};
		for (KVS const& k_pkg_name : k_command) {
			if (!kvs::is_string(k_pkg_name) || kvs::string_size(k_pkg_name) == 0) {
				TOGO_LOG("error: expected non-empty string argument\n");
				return false;
			}
			fixed_array::push_back(package_names, kvs::string_ref(k_pkg_name));
		}
		return interface::command_list(
			interface,
			false,
			fixed_array::begin(package_names),
			fixed_array::size(package_names)
		);
	}
}

} // namespace tool_build
} // namespace togo
<|endoftext|>


<commit_before>// (c) ZaKlaus 2016; Apache 2 Licensed, see LICENSE;;

#if !defined(DZM_H)

#define _CRT_SECURE_NO_WARNINGS

#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#include <float.h>

#define __STDC_FORMAT_MACROS
#include <inttypes.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#if defined(__linux)
#include <readline/readline.h>
#include <readline/history.h>

static inline FILE *
read_input(FILE *Stream)
{

    char *Buffer = readline("");
    FILE *NewStream = Stream;

    if(Buffer[0] != 0)
    {
        add_history(Buffer);
        NewStream = fmemopen((void *)Buffer, strlen(Buffer), "r");
    }

    return(NewStream);
}
#else
static inline FILE *
read_input(FILE *Stream)
{
    return(Stream);
}
#endif

typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef int32 bool32;

typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;

typedef intptr_t intptr;
typedef uintptr_t uintptr;

typedef size_t memory_index;
typedef size_t mi;

typedef float real32;
typedef double real64;

typedef int8 s8;
typedef int8 s08;
typedef int16 s16;
typedef int32 s32;
typedef int64 s64;
typedef bool32 b32;

typedef uint8 u8;
typedef uint8 u08;
typedef uint16 u16;
typedef uint32 u32;
typedef uint64 u64;

typedef real32 r32;
typedef real64 r64;

typedef uintptr_t umm;

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

#if !defined(COMPILER_MSVC)
#define COMPILER_MSVC 0
#endif

#if !defined(COMPILER_LLVM)
#define COMPILER_LLVM 0
#endif

#include "../dzm_ver.hpp"

#define MAKE(Type, Value) make_object(Type, (void *)&Value)
#define MAKE1(Type, Value, Value1) make_object(Type, (void *)&Value, (void *)&Value1)
#define MAKE2(Type, Value, Value1, Value2) make_object(Type, (void *)&Value, (void *)&Value1, (void *)&Value2)
#define MAKE3(Type, Value, Value1, Value2, Value3) make_object(Type, (void *)&Value, (void *)&Value1, (void *)&Value2, (void *)&Value3)

#ifdef COMPILER_MSVC
#define TRAP() *(int *)0 = 0
#elif COMPILER_LLVM
#define TRAP() __builtin_trap()
#else
#define TRAP() volatile *(int *)0 = 0
#endif

#define IGNORE(x) x

#ifdef DZM_SLOW
#define zassert(Expression) if(!(Expression)) {TRAP();}
#else
#define zassert(Expression)
#endif

#define InvalidCodePath zassert(!"InvalidCodePath")
#define InvalidDefaultCase default: {InvalidCodePath;} break
#define Unreachable(Statement) return(Statement)

#define Kilobytes(Value) ((Value)*1024LL)
#define Megabytes(Value) (Kilobytes(Value)*1024LL)
#define Gigabytes(Value) (Megabytes(Value)*1024LL)
#define Terabytes(Value) (Gigabytes(Value)*1024LL)

#define AlignPow2(Value, Alignment) ((Value + ((Alignment) - 1)) & ~((Alignment) - 1))
#define Align4(Value) ((Value + 3) & ~3)
#define Align8(Value) ((Value + 7) & ~7)
#define Align16(Value) ((Value + 15) & ~15)

#define STRINGIFY(X) #X
#define CONCAT(X,Y) X##Y
#define SQUOTE(X, I, C) char __s_quote__I; sprintf(__s_quote__I, "'%s'", X); C =
#define UL_ (u8 *)
#define L_  (s8 *)

#define MAX_VM_SIZE     4096 * 1024 * 32

static inline void
zero_size(memory_index Size, void *Ptr)
{
    uint8 *Byte = (uint8 *)Ptr;
    while(Size--)
    {
        *Byte++ = 0;
    }
}

#define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0]))

#ifdef DZM_ELEVATED
#undef _ELEVATED
#define _ELEVATED 1
#else
#undef _ELEVATED
#define _ELEVATED 0
#endif

// == Memory Manager
#include "dzm_mem.hpp"

// == Util
#include "dzm_utl.hpp"
#include "dzm_log.hpp"

// == Interpreter
#include "lang/dzm_mdl.hpp"
#include "lang/dzm_lex.hpp"
#include "lang/dzm_evl.hpp"
#include "lang/dzm_prt.hpp"
#include "lang/dzm_rep.hpp"

#define DZM_H
#endif<commit_msg>Fixed Mac OS X TRAP() problem on GCC compiler.<commit_after>// (c) ZaKlaus 2016; Apache 2 Licensed, see LICENSE;;

#if !defined(DZM_H)

#define _CRT_SECURE_NO_WARNINGS

#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#include <float.h>

#define __STDC_FORMAT_MACROS
#include <inttypes.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#if defined(__linux)
#include <readline/readline.h>
#include <readline/history.h>

static inline FILE *
read_input(FILE *Stream)
{

    char *Buffer = readline("");
    FILE *NewStream = Stream;

    if(Buffer[0] != 0)
    {
        add_history(Buffer);
        NewStream = fmemopen((void *)Buffer, strlen(Buffer), "r");
    }

    return(NewStream);
}
#else
static inline FILE *
read_input(FILE *Stream)
{
    return(Stream);
}
#endif

typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef int32 bool32;

typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;

typedef intptr_t intptr;
typedef uintptr_t uintptr;

typedef size_t memory_index;
typedef size_t mi;

typedef float real32;
typedef double real64;

typedef int8 s8;
typedef int8 s08;
typedef int16 s16;
typedef int32 s32;
typedef int64 s64;
typedef bool32 b32;

typedef uint8 u8;
typedef uint8 u08;
typedef uint16 u16;
typedef uint32 u32;
typedef uint64 u64;

typedef real32 r32;
typedef real64 r64;

typedef uintptr_t umm;

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

#if !defined(COMPILER_MSVC)
#define COMPILER_MSVC 0
#endif

#if !defined(COMPILER_LLVM)
#define COMPILER_LLVM 0
#endif

#include "../dzm_ver.hpp"

#define MAKE(Type, Value) make_object(Type, (void *)&Value)
#define MAKE1(Type, Value, Value1) make_object(Type, (void *)&Value, (void *)&Value1)
#define MAKE2(Type, Value, Value1, Value2) make_object(Type, (void *)&Value, (void *)&Value1, (void *)&Value2)
#define MAKE3(Type, Value, Value1, Value2, Value3) make_object(Type, (void *)&Value, (void *)&Value1, (void *)&Value2, (void *)&Value3)

#ifdef COMPILER_MSVC
#define TRAP() *(int *)0 = 0
#elif COMPILER_LLVM
#define TRAP() __builtin_trap()
#else
#ifdef __APPLE__
#define TRAP() __builtin_trap()
#else
#define TRAP() volatile *(int *)0 = 0
#endif

#define IGNORE(x) x

#ifdef DZM_SLOW
#define zassert(Expression) if(!(Expression)) {TRAP();}
#else
#define zassert(Expression)
#endif

#define InvalidCodePath zassert(!"InvalidCodePath")
#define InvalidDefaultCase default: {InvalidCodePath;} break
#define Unreachable(Statement) return(Statement)

#define Kilobytes(Value) ((Value)*1024LL)
#define Megabytes(Value) (Kilobytes(Value)*1024LL)
#define Gigabytes(Value) (Megabytes(Value)*1024LL)
#define Terabytes(Value) (Gigabytes(Value)*1024LL)

#define AlignPow2(Value, Alignment) ((Value + ((Alignment) - 1)) & ~((Alignment) - 1))
#define Align4(Value) ((Value + 3) & ~3)
#define Align8(Value) ((Value + 7) & ~7)
#define Align16(Value) ((Value + 15) & ~15)

#define STRINGIFY(X) #X
#define CONCAT(X,Y) X##Y
#define SQUOTE(X, I, C) char __s_quote__I; sprintf(__s_quote__I, "'%s'", X); C =
#define UL_ (u8 *)
#define L_  (s8 *)

#define MAX_VM_SIZE     4096 * 1024 * 32

static inline void
zero_size(memory_index Size, void *Ptr)
{
    uint8 *Byte = (uint8 *)Ptr;
    while(Size--)
    {
        *Byte++ = 0;
    }
}

#define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0]))

#ifdef DZM_ELEVATED
#undef _ELEVATED
#define _ELEVATED 1
#else
#undef _ELEVATED
#define _ELEVATED 0
#endif

// == Memory Manager
#include "dzm_mem.hpp"

// == Util
#include "dzm_utl.hpp"
#include "dzm_log.hpp"

// == Interpreter
#include "lang/dzm_mdl.hpp"
#include "lang/dzm_lex.hpp"
#include "lang/dzm_evl.hpp"
#include "lang/dzm_prt.hpp"
#include "lang/dzm_rep.hpp"

#define DZM_H
#endif<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008, 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <iconv.h>
#include <errno.h>
#include <sstream>
#include <boost/algorithm/string.hpp>
#include "flusspferd/binary.hpp"
#include "flusspferd/encodings.hpp"
#include "flusspferd/create.hpp"

using namespace boost;
using namespace flusspferd;

void flusspferd::load_encodings_module(object container) {
  object exports = container.get_property_object("exports");

  // Load the binary module
  global().call("require", "binary");

  create_native_function(
    exports,
    "convertToString", &encodings::convert_to_string);

  create_native_function(
    exports,
    "convertFromString", &encodings::convert_from_string);

  create_native_function( exports, "convert", &encodings::convert);
}

// HELPER METHODS

// Actually do the conversion.
binary::vector_type do_convert(iconv_t conv, binary::vector_type const &in);

// call iconv_open, or throw an error if it cant
iconv_t open_convert(std::string const &from, std::string const &to);

// If no direct conversion is possible, do it via utf8. Helper method
object convert_via_utf8(std::string toEnc, std::string fromEnc,
                        binary const &source);

string
encodings::convert_to_string(std::string &enc, binary &source_binary) {

  binary::vector_type const &source = source_binary.get_const_data();

  to_lower(enc);
  if (enc == "utf-8") {
    binary::vector_type const &source = source_binary.get_const_data();
    return string( (char*)&source[0], source.size());
  }
  else if (enc == "utf-16") {
    // TODO: Assert on the possible alignment issue here
    binary::vector_type const &source = source_binary.get_const_data();
    return string( reinterpret_cast<char16_t const*>(&source[0]), source.size()/2);
  }
  else {
    // Not UTF-8 or UTF-16, so convert to utf-16

    // Except UTF-8 seems to suffer from a byte order issue. UTF-8 is less
    // error prone it seems. FIXME
    iconv_t conv = open_convert(enc, "utf-8");
    binary::vector_type utf16 = do_convert(conv, source);
    iconv_close(conv);
    return string( reinterpret_cast<char const*>(&utf16[0]), utf16.size());
  }
  return string();
}

object
encodings::convert_from_string(std::string &, binary const &) {
  size_t n = 0;
  return create_native_object<byte_string>(object(), (unsigned char*)"", n);
}

object encodings::convert(std::string &from, std::string &to,
    binary &source_binary)
{
  binary::vector_type const &source = source_binary.get_const_data();

  to_lower(from);
  to_lower(to);
  if ( from == to ) {
    // Encodings are the same, just return a copy of the binary
    return create_native_object<byte_string>(
      object(),
      &source[0],
      source.size()
    );
  }

  iconv_t conv = open_convert(from, to);

  binary::vector_type buf = do_convert(conv, source);
  iconv_close(conv);
  return create_native_object<byte_string>(object(), &buf[0], buf.size());
}
// End JS methods

binary::vector_type
do_convert(iconv_t conv, binary::vector_type const &source) {
  binary::vector_type outbuf;

  size_t out_left,
         in_left = source.size();

  out_left = in_left + in_left/16 + 32; // GPSEE's Wild-assed guess.

  outbuf.resize(out_left);

  const unsigned char *inbytes  = &source[0],
                      *outbytes = &outbuf[0];

  while (in_left) {
    size_t n = iconv(conv,
                     (char**)&inbytes, &in_left,
                     (char**)&outbytes, &out_left
                    );

    if (n == (size_t)(-1)) {
      switch (errno) {
        case E2BIG:
          // Not enough space in output
          // Use GPSEE's WAG again. +32 assumes no encoding needs more than 32
          // bytes(!) pre character. Probably a safe bet.
          size_t new_size = in_left + in_left/4 + 32,
                 old_size = outbytes - &outbuf[0];

          outbuf.resize(old_size + new_size);

          // The vector has probably realloced, so recalculate outbytes
          outbytes =  &outbuf[old_size];
          out_left += new_size;

          continue;

        case EILSEQ:
          // An invalid multibyte sequence has been encountered in the input.
        case EINVAL:
          // An incomplete multibyte sequence has been encountered in the input.

          // Since we have provided the entire input, both these cases are the
          // same.
          throw flusspferd::exception("convert error", "TypeError");
          break;
      }
    }

    // Else all chars got converted
    in_left -= n;
  }
  outbuf.resize(outbytes - &outbuf[0]);
  return outbuf;
}

iconv_t open_convert(std::string const &from, std::string const &to) {
  iconv_t conv = iconv_open(to.c_str(), from.c_str());

  if (conv == (iconv_t)(-1)) {
    std::stringstream ss;
    ss << "Unable to convert from \"" << from
       << "\" to \"" << to << "\"";
    throw flusspferd::exception(ss.str().c_str());
  }
  return conv;
}

object
convert_via_utf8(std::string const &to, std::string const &from,
                 binary const &) {
  iconv_t to_utf   = iconv_open("utf-8", from.c_str()),
          from_utf = iconv_open(to.c_str(), "utf-8");

  if (to_utf == (iconv_t)(-1) || from_utf == (iconv_t)(-1)) {

    if (to_utf)
      iconv_close(to_utf);
    if (from_utf)
      iconv_close(from_utf);

    std::stringstream ss;
    ss << "Unable to convert from \"" << from
       << "\" to \"" << to << "\"";
    throw flusspferd::exception(ss.str().c_str());
  }
  return object();
}
<commit_msg>core/encodings: add {} block to make the compiler not complain<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008, 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <iconv.h>
#include <errno.h>
#include <sstream>
#include <boost/algorithm/string.hpp>
#include "flusspferd/binary.hpp"
#include "flusspferd/encodings.hpp"
#include "flusspferd/create.hpp"

using namespace boost;
using namespace flusspferd;

void flusspferd::load_encodings_module(object container) {
  object exports = container.get_property_object("exports");

  // Load the binary module
  global().call("require", "binary");

  create_native_function(
    exports,
    "convertToString", &encodings::convert_to_string);

  create_native_function(
    exports,
    "convertFromString", &encodings::convert_from_string);

  create_native_function( exports, "convert", &encodings::convert);
}

// HELPER METHODS

// Actually do the conversion.
binary::vector_type do_convert(iconv_t conv, binary::vector_type const &in);

// call iconv_open, or throw an error if it cant
iconv_t open_convert(std::string const &from, std::string const &to);

// If no direct conversion is possible, do it via utf8. Helper method
object convert_via_utf8(std::string toEnc, std::string fromEnc,
                        binary const &source);

string
encodings::convert_to_string(std::string &enc, binary &source_binary) {

  binary::vector_type const &source = source_binary.get_const_data();

  to_lower(enc);
  if (enc == "utf-8") {
    binary::vector_type const &source = source_binary.get_const_data();
    return string( (char*)&source[0], source.size());
  }
  else if (enc == "utf-16") {
    // TODO: Assert on the possible alignment issue here
    binary::vector_type const &source = source_binary.get_const_data();
    return string( reinterpret_cast<char16_t const*>(&source[0]), source.size()/2);
  }
  else {
    // Not UTF-8 or UTF-16, so convert to utf-16

    // Except UTF-8 seems to suffer from a byte order issue. UTF-8 is less
    // error prone it seems. FIXME
    iconv_t conv = open_convert(enc, "utf-8");
    binary::vector_type utf16 = do_convert(conv, source);
    iconv_close(conv);
    return string( reinterpret_cast<char const*>(&utf16[0]), utf16.size());
  }
  return string();
}

object
encodings::convert_from_string(std::string &, binary const &) {
  size_t n = 0;
  return create_native_object<byte_string>(object(), (unsigned char*)"", n);
}

object encodings::convert(std::string &from, std::string &to,
    binary &source_binary)
{
  binary::vector_type const &source = source_binary.get_const_data();

  to_lower(from);
  to_lower(to);
  if ( from == to ) {
    // Encodings are the same, just return a copy of the binary
    return create_native_object<byte_string>(
      object(),
      &source[0],
      source.size()
    );
  }

  iconv_t conv = open_convert(from, to);

  binary::vector_type buf = do_convert(conv, source);
  iconv_close(conv);
  return create_native_object<byte_string>(object(), &buf[0], buf.size());
}
// End JS methods

binary::vector_type
do_convert(iconv_t conv, binary::vector_type const &source) {
  binary::vector_type outbuf;

  size_t out_left,
         in_left = source.size();

  out_left = in_left + in_left/16 + 32; // GPSEE's Wild-assed guess.

  outbuf.resize(out_left);

  const unsigned char *inbytes  = &source[0],
                      *outbytes = &outbuf[0];

  while (in_left) {
    size_t n = iconv(conv,
                     (char**)&inbytes, &in_left,
                     (char**)&outbytes, &out_left
                    );

    if (n == (size_t)(-1)) {
      switch (errno) {
        case E2BIG: {
          // Not enough space in output
          // Use GPSEE's WAG again. +32 assumes no encoding needs more than 32
          // bytes(!) per character. Probably a safe bet.
          size_t new_size = in_left + in_left/4 + 32,
                 old_size = outbytes - &outbuf[0];

          outbuf.resize(old_size + new_size);

          // The vector has probably realloced, so recalculate outbytes
          outbytes =  &outbuf[old_size];
          out_left += new_size;

          continue;
        }

        case EILSEQ:
          // An invalid multibyte sequence has been encountered in the input.
        case EINVAL:
          // An incomplete multibyte sequence has been encountered in the input.

          // Since we have provided the entire input, both these cases are the
          // same.
          throw flusspferd::exception("convert error", "TypeError");
          break;
      }
    }

    // Else all chars got converted
    in_left -= n;
  }
  outbuf.resize(outbytes - &outbuf[0]);
  return outbuf;
}

iconv_t open_convert(std::string const &from, std::string const &to) {
  iconv_t conv = iconv_open(to.c_str(), from.c_str());

  if (conv == (iconv_t)(-1)) {
    std::stringstream ss;
    ss << "Unable to convert from \"" << from
       << "\" to \"" << to << "\"";
    throw flusspferd::exception(ss.str().c_str());
  }
  return conv;
}

object
convert_via_utf8(std::string const &to, std::string const &from,
                 binary const &) {
  iconv_t to_utf   = iconv_open("utf-8", from.c_str()),
          from_utf = iconv_open(to.c_str(), "utf-8");

  if (to_utf == (iconv_t)(-1) || from_utf == (iconv_t)(-1)) {

    if (to_utf)
      iconv_close(to_utf);
    if (from_utf)
      iconv_close(from_utf);

    std::stringstream ss;
    ss << "Unable to convert from \"" << from
       << "\" to \"" << to << "\"";
    throw flusspferd::exception(ss.str().c_str());
  }
  return object();
}
<|endoftext|>


<commit_before>#include "FunctionCallOperatorNode.h"
#include "../../Parser.h"

#include <assert.h>

namespace Three {
    FunctionCallOperatorNode* FunctionCallOperatorNode::parse(Parser& parser, ASTNode* receiver) {
        FunctionCallOperatorNode* node = new FunctionCallOperatorNode();

        node->_receiver = receiver;
        node->setOp("()");

        assert(parser.next().type() == Token::Type::PunctuationOpenParen);

        // now, we need to parse the arguments, each of which
        // is an expression
        parser.parseUntil(true, [&] (const Token& token) {
            if (token.type() == Token::Type::PunctuationCloseParen) {
                return true;
            }

            node->addChild(parser.parseExpression());

            // if we run into a comma, parse it and return false
            return !parser.nextIf(",");
        });

        // here we've ended including parsing the close-paren

        if (parser.peek().type() == Token::Type::Newline) {
            node->setStatement(true);
        }

        return node;
    }

    ASTNode* FunctionCallOperatorNode::receiver() const {
        return _receiver;
    }

    TypeReference FunctionCallOperatorNode::receiverNodeType() const {
        if (this->receiverIsClosure()) {
            // TODO: this is a crazy hack to make sure that
            // our indirection level is correct for calling closures
            TypeReference ref = _receiver->nodeType();

            ref.incrementIndirectionDepth();

            return ref;
        }

        return _receiver->nodeType();
    }

    bool FunctionCallOperatorNode::receiverIsClosure() const {
        assert(_receiver);
        assert(_receiver->nodeType().referencedType());

        return _receiver->nodeType().referencedType()->flavor() == DataType::Flavor::Closure;
    }

    void FunctionCallOperatorNode::codeGen(CSourceContext& context) {
        if (this->receiverIsClosure()) {
            context << "THREE_CALL_CLOSURE(";
            this->_receiver->nodeType().codeGenFunction(context, "");
            context << ", ";
            this->_receiver->codeGen(context);

            if (this->childCount() > 0) {
                context << ", ";
            }
        } else {
            this->_receiver->codeGen(context);
            context << "(";
        }

        this->eachChildWithLast([=, &context] (ASTNode* node, bool last) {
            node->codeGen(context);
            if (!last) {
                context << ", ";
            }
        });

        context << ")";
    }
}
<commit_msg>Small change to make it possible to call c-imported function-like macros in more situations<commit_after>#include "FunctionCallOperatorNode.h"
#include "../../Parser.h"

#include <assert.h>

namespace Three {
    FunctionCallOperatorNode* FunctionCallOperatorNode::parse(Parser& parser, ASTNode* receiver) {
        FunctionCallOperatorNode* node = new FunctionCallOperatorNode();

        node->_receiver = receiver;
        node->setOp("()");

        assert(parser.next().type() == Token::Type::PunctuationOpenParen);

        // now, we need to parse the arguments, each of which
        // is an expression
        parser.parseUntil(true, [&] (const Token& token) {
            if (token.type() == Token::Type::PunctuationCloseParen) {
                return true;
            }

            node->addChild(parser.parseExpression());

            // if we run into a comma, parse it and return false
            return !parser.nextIf(",");
        });

        // here we've ended including parsing the close-paren

        if (parser.peek().type() == Token::Type::Newline) {
            node->setStatement(true);
        }

        return node;
    }

    ASTNode* FunctionCallOperatorNode::receiver() const {
        return _receiver;
    }

    TypeReference FunctionCallOperatorNode::receiverNodeType() const {
        if (this->receiverIsClosure()) {
            // TODO: this is a crazy hack to make sure that
            // our indirection level is correct for calling closures
            TypeReference ref = _receiver->nodeType();

            ref.incrementIndirectionDepth();

            return ref;
        }

        return _receiver->nodeType();
    }

    bool FunctionCallOperatorNode::receiverIsClosure() const {
        assert(_receiver);

        if (!_receiver->nodeType().referencedType()) {
            return false;
        }

        return _receiver->nodeType().referencedType()->flavor() == DataType::Flavor::Closure;
    }

    void FunctionCallOperatorNode::codeGen(CSourceContext& context) {
        if (this->receiverIsClosure()) {
            context << "THREE_CALL_CLOSURE(";
            this->_receiver->nodeType().codeGenFunction(context, "");
            context << ", ";
            this->_receiver->codeGen(context);

            if (this->childCount() > 0) {
                context << ", ";
            }
        } else {
            this->_receiver->codeGen(context);
            context << "(";
        }

        this->eachChildWithLast([=, &context] (ASTNode* node, bool last) {
            node->codeGen(context);
            if (!last) {
                context << ", ";
            }
        });

        context << ")";
    }
}
<|endoftext|>


<commit_before>#include <occa/core/device.hpp>
#include <occa/core/memory.hpp>
#include <occa/core/kernelArg.hpp>
#include <occa/tools/uva.hpp>

namespace occa {
  //---[ KernelArg ]--------------------
  const nullKernelArg_t nullKernelArg;

  kernelArgData::kernelArgData() :
    modeMemory(NULL),
    size(0),
    info(kArgInfo::none) {
    ::memset(&data, 0, sizeof(data));
  }

  kernelArgData::kernelArgData(const kernelArgData &other) :
      modeMemory(other.modeMemory),
      data(other.data),
      size(other.size),
      info(other.info) {}

  kernelArgData& kernelArgData::operator = (const kernelArgData &other) {
    modeMemory = other.modeMemory;

    data = other.data;
    size = other.size;
    info = other.info;

    return *this;
  }

  kernelArgData::~kernelArgData() {}

  occa::modeDevice_t* kernelArgData::getModeDevice() const {
    if (!modeMemory) {
      return NULL;
    }
    return modeMemory->modeDevice;
  }

  occa::modeMemory_t* kernelArgData::getModeMemory() const {
    return modeMemory;
  }

  void* kernelArgData::ptr() const {
    if (!isNull()) {
      if (info & kArgInfo::usePointer) {
        return data.void_;
      } else {
        return (void*) &data;
      }
    }
    return NULL;
  }

  bool kernelArgData::isNull() const {
    return (info & kArgInfo::isNull);
  }

  void kernelArgData::setupForKernelCall(const bool isConst) const {
    if (!modeMemory              ||
        !modeMemory->isManaged() ||
        !modeMemory->modeDevice->hasSeparateMemorySpace()) {
      return;
    }
    if (!modeMemory->inDevice()) {
      modeMemory->copyFrom(modeMemory->uvaPtr, modeMemory->size);
      modeMemory->memInfo |= uvaFlag::inDevice;
    }
    if (!isConst && !modeMemory->isStale()) {
      uvaStaleMemory.push_back(modeMemory);
      modeMemory->memInfo |= uvaFlag::isStale;
    }
  }

  kernelArg::kernelArg() {}
  kernelArg::~kernelArg() {}

  kernelArg::kernelArg(const kernelArgData &arg) {
    args.push_back(arg);
  }

  kernelArg::kernelArg(const kernelArg &other) :
      args(other.args) {}

  kernelArg& kernelArg::operator = (const kernelArg &other) {
    args = other.args;
    return *this;
  }

  template <>
  kernelArg::kernelArg(modeMemory_t *arg) {
    if (arg) {
      add(arg->makeKernelArg());
    } else {
      add(kernelArg(nullKernelArg));
    }
  }

  template <>
  kernelArg::kernelArg(const modeMemory_t *arg) {
    add(arg->makeKernelArg());
  }

  int kernelArg::size() const {
    return (int) args.size();
  }

  device kernelArg::getDevice() const {
    const int argCount = (int) args.size();

    for (int i = 0; i < argCount; ++i) {
      const kernelArgData &arg = args[i];
      if (arg.modeMemory) {
        return device(arg.modeMemory->modeDevice);
      }
    }

    return device();
  }

  const kernelArgData& kernelArg::operator [] (const int index) const {
    return args[index];
  }

  kernelArg::kernelArg(const nullKernelArg_t arg) {
    kernelArgData kArg;
    kArg.data.void_ = NULL;
    kArg.size       = sizeof(void*);
    kArg.info       = (
      kArgInfo::usePointer
      | kArgInfo::isNull
    );
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const uint8_t arg) {
    kernelArgData kArg;
    kArg.data.uint8_ = arg;
    kArg.size        = sizeof(uint8_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const uint16_t arg) {
    kernelArgData kArg;
    kArg.data.uint16_ = arg;
    kArg.size         = sizeof(uint16_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const uint32_t arg) {
    kernelArgData kArg;
    kArg.data.uint32_ = arg;
    kArg.size         = sizeof(uint32_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const uint64_t arg) {
    kernelArgData kArg;
    kArg.data.uint64_ = arg;
    kArg.size         = sizeof(uint64_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const int8_t arg) {
    kernelArgData kArg;
    kArg.data.int8_ = arg;
    kArg.size       = sizeof(int8_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const int16_t arg) {
    kernelArgData kArg;
    kArg.data.int16_ = arg;
    kArg.size        = sizeof(int16_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const int32_t arg) {
    kernelArgData kArg;
    kArg.data.int32_ = arg;
    kArg.size        = sizeof(int32_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const int64_t arg) {
    kernelArgData kArg;
    kArg.data.int64_ = arg;
    kArg.size        = sizeof(int64_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const float arg) {
    kernelArgData kArg;
    kArg.data.float_ = arg;
    kArg.size         = sizeof(float);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const double arg) {
    kernelArgData kArg;
    kArg.data.double_ = arg;
    kArg.size         = sizeof(double);
    args.push_back(kArg);
  }

  void kernelArg::add(const kernelArg &arg) {
    const int newArgs = (int) arg.args.size();
    for (int i = 0; i < newArgs; ++i) {
      args.push_back(arg.args[i]);
    }
  }

  void kernelArg::add(void *arg,
                      bool lookAtUva, bool argIsUva) {
    add(arg, sizeof(void*), lookAtUva, argIsUva);
  }

  void kernelArg::add(void *arg, size_t bytes,
                      bool lookAtUva, bool argIsUva) {
    modeMemory_t *modeMemory = NULL;

    if (argIsUva) {
      modeMemory = (modeMemory_t*) arg;
    } else if (lookAtUva) {
      ptrRangeMap::iterator it = uvaMap.find(arg);
      if (it != uvaMap.end()) {
        modeMemory = it->second;
      }
    }

    if (modeMemory) {
      add(modeMemory->makeKernelArg());
    } else if (arg != NULL) {
      kernelArgData kArg;
      kArg.data.void_ = arg;
      kArg.size       = bytes;
      kArg.info       = kArgInfo::usePointer;
      args.push_back(kArg);
    }
  }

  int kernelArg::argumentCount(const std::vector<kernelArg> &arguments) {
    const int kArgCount = (int) arguments.size();
    int argc = 0;
    for (int i = 0; i < kArgCount; ++i) {
      argc += arguments[i].args.size();
    }
    return argc;
  }
  //====================================
}
<commit_msg>[Memory] Fixes the null case when memory size is 0<commit_after>#include <occa/core/device.hpp>
#include <occa/core/memory.hpp>
#include <occa/core/kernelArg.hpp>
#include <occa/tools/uva.hpp>

namespace occa {
  //---[ KernelArg ]--------------------
  const nullKernelArg_t nullKernelArg;

  kernelArgData::kernelArgData() :
    modeMemory(NULL),
    size(0),
    info(kArgInfo::none) {
    ::memset(&data, 0, sizeof(data));
  }

  kernelArgData::kernelArgData(const kernelArgData &other) :
      modeMemory(other.modeMemory),
      data(other.data),
      size(other.size),
      info(other.info) {}

  kernelArgData& kernelArgData::operator = (const kernelArgData &other) {
    modeMemory = other.modeMemory;

    data = other.data;
    size = other.size;
    info = other.info;

    return *this;
  }

  kernelArgData::~kernelArgData() {}

  occa::modeDevice_t* kernelArgData::getModeDevice() const {
    if (!modeMemory) {
      return NULL;
    }
    return modeMemory->modeDevice;
  }

  occa::modeMemory_t* kernelArgData::getModeMemory() const {
    return modeMemory;
  }

  void* kernelArgData::ptr() const {
    if (!isNull()) {
      if (info & kArgInfo::usePointer) {
        return data.void_;
      } else {
        return (void*) &data;
      }
    }
    return NULL;
  }

  bool kernelArgData::isNull() const {
    return (info & kArgInfo::isNull);
  }

  void kernelArgData::setupForKernelCall(const bool isConst) const {
    if (!modeMemory              ||
        !modeMemory->isManaged() ||
        !modeMemory->modeDevice->hasSeparateMemorySpace()) {
      return;
    }
    if (!modeMemory->inDevice()) {
      modeMemory->copyFrom(modeMemory->uvaPtr, modeMemory->size);
      modeMemory->memInfo |= uvaFlag::inDevice;
    }
    if (!isConst && !modeMemory->isStale()) {
      uvaStaleMemory.push_back(modeMemory);
      modeMemory->memInfo |= uvaFlag::isStale;
    }
  }

  kernelArg::kernelArg() {}
  kernelArg::~kernelArg() {}

  kernelArg::kernelArg(const kernelArgData &arg) {
    args.push_back(arg);
  }

  kernelArg::kernelArg(const kernelArg &other) :
      args(other.args) {}

  kernelArg& kernelArg::operator = (const kernelArg &other) {
    args = other.args;
    return *this;
  }

  template <>
  kernelArg::kernelArg(modeMemory_t *arg) {
    if (arg && arg->size) {
      add(arg->makeKernelArg());
    } else {
      add(kernelArg(nullKernelArg));
    }
  }

  template <>
  kernelArg::kernelArg(const modeMemory_t *arg) {
    add(arg->makeKernelArg());
  }

  int kernelArg::size() const {
    return (int) args.size();
  }

  device kernelArg::getDevice() const {
    const int argCount = (int) args.size();

    for (int i = 0; i < argCount; ++i) {
      const kernelArgData &arg = args[i];
      if (arg.modeMemory) {
        return device(arg.modeMemory->modeDevice);
      }
    }

    return device();
  }

  const kernelArgData& kernelArg::operator [] (const int index) const {
    return args[index];
  }

  kernelArg::kernelArg(const nullKernelArg_t arg) {
    kernelArgData kArg;
    kArg.data.void_ = NULL;
    kArg.size       = sizeof(void*);
    kArg.info       = (
      kArgInfo::usePointer
      | kArgInfo::isNull
    );
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const uint8_t arg) {
    kernelArgData kArg;
    kArg.data.uint8_ = arg;
    kArg.size        = sizeof(uint8_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const uint16_t arg) {
    kernelArgData kArg;
    kArg.data.uint16_ = arg;
    kArg.size         = sizeof(uint16_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const uint32_t arg) {
    kernelArgData kArg;
    kArg.data.uint32_ = arg;
    kArg.size         = sizeof(uint32_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const uint64_t arg) {
    kernelArgData kArg;
    kArg.data.uint64_ = arg;
    kArg.size         = sizeof(uint64_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const int8_t arg) {
    kernelArgData kArg;
    kArg.data.int8_ = arg;
    kArg.size       = sizeof(int8_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const int16_t arg) {
    kernelArgData kArg;
    kArg.data.int16_ = arg;
    kArg.size        = sizeof(int16_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const int32_t arg) {
    kernelArgData kArg;
    kArg.data.int32_ = arg;
    kArg.size        = sizeof(int32_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const int64_t arg) {
    kernelArgData kArg;
    kArg.data.int64_ = arg;
    kArg.size        = sizeof(int64_t);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const float arg) {
    kernelArgData kArg;
    kArg.data.float_ = arg;
    kArg.size         = sizeof(float);
    args.push_back(kArg);
  }

  kernelArg::kernelArg(const double arg) {
    kernelArgData kArg;
    kArg.data.double_ = arg;
    kArg.size         = sizeof(double);
    args.push_back(kArg);
  }

  void kernelArg::add(const kernelArg &arg) {
    const int newArgs = (int) arg.args.size();
    for (int i = 0; i < newArgs; ++i) {
      args.push_back(arg.args[i]);
    }
  }

  void kernelArg::add(void *arg,
                      bool lookAtUva, bool argIsUva) {
    add(arg, sizeof(void*), lookAtUva, argIsUva);
  }

  void kernelArg::add(void *arg, size_t bytes,
                      bool lookAtUva, bool argIsUva) {
    modeMemory_t *modeMemory = NULL;

    if (argIsUva) {
      modeMemory = (modeMemory_t*) arg;
    } else if (lookAtUva) {
      ptrRangeMap::iterator it = uvaMap.find(arg);
      if (it != uvaMap.end()) {
        modeMemory = it->second;
      }
    }

    if (modeMemory) {
      add(modeMemory->makeKernelArg());
    } else if (arg != NULL) {
      kernelArgData kArg;
      kArg.data.void_ = arg;
      kArg.size       = bytes;
      kArg.info       = kArgInfo::usePointer;
      args.push_back(kArg);
    }
  }

  int kernelArg::argumentCount(const std::vector<kernelArg> &arguments) {
    const int kArgCount = (int) arguments.size();
    int argc = 0;
    for (int i = 0; i < kArgCount; ++i) {
      argc += arguments[i].args.size();
    }
    return argc;
  }
  //====================================
}
<|endoftext|>


<commit_before>// RUN: %clangxx -fsanitize=undefined -O0 %s -o %t && UBSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=1 %run %t 2>&1 | FileCheck %s
// RUN: %clangxx -fsanitize=undefined -O0 %s -o %t && UBSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=0 %run %t 2>&1 | FileCheck %s

// The test doesn't pass on Darwin in UBSan-TSan configuration, because TSan is
// using the slow unwinder which is not supported on Darwin. The test should
// be universal after landing of https://reviews.llvm.org/D32806.

#include <sanitizer/common_interface_defs.h>

static inline void FooBarBaz() {
  __sanitizer_print_stack_trace();
}

int main() {
  FooBarBaz();
  return 0;
}

// CHECK: {{.*}} in FooBarBaz{{.*}}print_stack_trace.cc{{.*}}
// CHECK: {{.*}} in main{{.*}}print_stack_trace.cc{{.*}}
<commit_msg>[ubsan]: temporarily disable print_stack_trace.cc test<commit_after>// RUN: %clangxx -fsanitize=undefined -O0 %s -o %t && UBSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=1 %run %t 2>&1 | FileCheck %s
// RUN: %clangxx -fsanitize=undefined -O0 %s -o %t && UBSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=0 %run %t 2>&1 | FileCheck %s

// This test is temporarily disabled due to broken unwinding on ARM.
// UNSUPPORTED: -linux-

// The test doesn't pass on Darwin in UBSan-TSan configuration, because TSan is
// using the slow unwinder which is not supported on Darwin. The test should
// be universal after landing of https://reviews.llvm.org/D32806.

#include <sanitizer/common_interface_defs.h>

static inline void FooBarBaz() {
  __sanitizer_print_stack_trace();
}

int main() {
  FooBarBaz();
  return 0;
}

// CHECK: {{.*}} in FooBarBaz{{.*}}print_stack_trace.cc{{.*}}
// CHECK: {{.*}} in main{{.*}}print_stack_trace.cc{{.*}}
<|endoftext|>