<commit_before>/************************************************************************/
/*                                                                      */
/*               Copyright 2001-2002 by Gunnar Kedenburg                */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    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.                                   */
/*                                                                      */
/************************************************************************/

/* Modifications by Pablo d'Angelo
 * updated to vigra 1.4 by Douglas Wilkins
 * as of 18 Febuary 2006:
 *  - Added UINT16 and UINT32 pixel types.
 *  - Added support for obtaining extra bands beyond RGB.
 *  - Added support for a position field that indicates the start of this
 *    image relative to some global origin.
 *  - Added support for x and y resolution fields.
 *  - Added support for ICC Profiles
 */

#ifndef VIGRA_CODEC_HXX
#define VIGRA_CODEC_HXX

#include <memory>
#include <string>
#include <vector>

#include "array_vector.hxx"
#include "config.hxx"
#include "diff2d.hxx"
#include "sized_int.hxx"

// possible pixel types:
// "undefined", "UINT8", "UINT16", "INT16", "UINT32", "INT32", "FLOAT", "DOUBLE"

// possible compression types:
// "undefined", "RLE", "LZW", "LOSSLESS", "JPEG", "DEFLATE"

// possible file types:
// "undefined", "TIFF", "VIFF", "JPEG", "PNG", "PNM", "BMP", "SUN", "XPM", "EXR"

// possible name extensions:
// "undefined", "tif", "tiff", "jpg", "jpeg", "png", "pnm", "bmp", "sun",
// "xpm", "exr" (also capital forms)

namespace vigra
{
    template <class T>
    struct TypeAsString
    {
        static std::string result() { return "undefined"; }
    };

    template <>
    struct TypeAsString<Int8>
    {
        static std::string result() { return "INT8"; }
    };

    template <>
    struct TypeAsString<UInt8>
    {
        static std::string result() { return "UINT8"; }
    };

    template <>
    struct TypeAsString<Int16>
    {
        static std::string result() { return "INT16"; }
    };

    template <>
    struct TypeAsString<UInt16>
    {
        static std::string result() { return "UINT16"; }
    };

    template <>
    struct TypeAsString<Int32>
    {
        static std::string result() { return "INT32"; }
    };

    template <>
    struct TypeAsString<UInt32>
    {
        static std::string result() { return "UINT32"; }
    };

    template <>
    struct TypeAsString<float>
    {
        static std::string result() { return "FLOAT"; }
    };

    template <>
    struct TypeAsString<double>
    {
        static std::string result() { return "DOUBLE"; }
    };

    // codec description
    struct CodecDesc
    {
        std::string fileType;
        std::vector<std::string> pixelTypes;
        std::vector<std::string> compressionTypes;
        std::vector<std::vector<char> > magicStrings;
        std::vector<std::string> fileExtensions;
        std::vector<int> bandNumbers;
    };

    // Decoder and Encoder are virtual types that define a common
    // interface for all image file formats impex supports.

    struct Decoder
    {
        virtual ~Decoder() {};
        virtual void init( const std::string & ) = 0;
        virtual void close() = 0;
        virtual void abort() = 0;

        virtual std::string getFileType() const = 0;
        virtual std::string getPixelType() const = 0;

        virtual unsigned int getWidth() const = 0;
        virtual unsigned int getHeight() const = 0;
        virtual unsigned int getNumBands() const = 0;
        virtual unsigned int getNumExtraBands() const
        {
            return 0;
        }

        virtual vigra::Diff2D getPosition() const
        {
            return vigra::Diff2D();
        }

        virtual float getXResolution() const
        {
            return 0.0f;
        }
        virtual float getYResolution() const
        {
            return 0.0f;
        }

        virtual vigra::Size2D getCanvasSize() const
        {
            return vigra::Size2D(this->getWidth(), this->getHeight());
        }

        virtual unsigned int getOffset() const = 0;

        virtual const void * currentScanlineOfBand( unsigned int ) const = 0;
        virtual void nextScanline() = 0;

        typedef ArrayVector<unsigned char> ICCProfile;

        const ICCProfile & getICCProfile() const
        {
            return iccProfile_;
        }

        ICCProfile iccProfile_;
    };

    struct Encoder
    {
        virtual ~Encoder() {};
        virtual void init( const std::string & ) = 0;
        virtual void close() = 0;
        virtual void abort() = 0;

        virtual std::string getFileType() const = 0;
        virtual unsigned int getOffset() const = 0;

        virtual void setWidth( unsigned int ) = 0;
        virtual void setHeight( unsigned int ) = 0;
        virtual void setNumBands( unsigned int ) = 0;
        virtual void setCompressionType( const std::string &, int = -1 ) = 0;
        virtual void setPixelType( const std::string & ) = 0;
        virtual void finalizeSettings() = 0;

        virtual void setPosition( const vigra::Diff2D & /*pos*/ )
        {
        }
        virtual void setCanvasSize( const vigra::Size2D & size)
        {
        }
        virtual void setXResolution( float /*xres*/ )
        {
        }
        virtual void setYResolution( float /*yres*/ )
        {
        }

        typedef ArrayVector<unsigned char> ICCProfile;

        virtual void setICCProfile(const ICCProfile & /* data */)
        {
        }

        virtual void * currentScanlineOfBand( unsigned int ) = 0;
        virtual void nextScanline() = 0;

        struct TIFFCompressionException {};
    };

    // codec factory for registration at the codec manager

    struct CodecFactory
    {
        virtual CodecDesc getCodecDesc() const = 0;
        virtual std::auto_ptr<Decoder> getDecoder() const = 0;
        virtual std::auto_ptr<Encoder> getEncoder() const = 0;
        virtual ~CodecFactory() {};
    };

    // factory functions to encapsulate the codec managers
    //
    // codecs are selected according to the following order:
    // - (if provided) the FileType
    // - (in case of decoders) the file's magic string
    // - the filename extension

    VIGRA_EXPORT std::auto_ptr<Decoder>
    getDecoder( const std::string &, const std::string & = "undefined" );

    VIGRA_EXPORT std::auto_ptr<Encoder>
    getEncoder( const std::string &, const std::string & = "undefined" );

    VIGRA_EXPORT std::string
    getEncoderType( const std::string &, const std::string & = "undefined" );

    // functions to query the capabilities of certain codecs

    VIGRA_EXPORT std::vector<std::string> queryCodecPixelTypes( const std::string & );

    VIGRA_EXPORT bool negotiatePixelType( std::string const & codecname,
                 std::string const & srcPixeltype, std::string & destPixeltype);

    VIGRA_EXPORT bool isPixelTypeSupported( const std::string &, const std::string & );

    VIGRA_EXPORT bool isBandNumberSupported( const std::string &, int bands );
}

#endif // VIGRA_CODEC_HXX
<commit_msg>cleanup compiler warning<commit_after>/************************************************************************/
/*                                                                      */
/*               Copyright 2001-2002 by Gunnar Kedenburg                */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    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.                                   */
/*                                                                      */
/************************************************************************/

/* Modifications by Pablo d'Angelo
 * updated to vigra 1.4 by Douglas Wilkins
 * as of 18 Febuary 2006:
 *  - Added UINT16 and UINT32 pixel types.
 *  - Added support for obtaining extra bands beyond RGB.
 *  - Added support for a position field that indicates the start of this
 *    image relative to some global origin.
 *  - Added support for x and y resolution fields.
 *  - Added support for ICC Profiles
 */

#ifndef VIGRA_CODEC_HXX
#define VIGRA_CODEC_HXX

#include <memory>
#include <string>
#include <vector>

#include "array_vector.hxx"
#include "config.hxx"
#include "diff2d.hxx"
#include "sized_int.hxx"

// possible pixel types:
// "undefined", "UINT8", "UINT16", "INT16", "UINT32", "INT32", "FLOAT", "DOUBLE"

// possible compression types:
// "undefined", "RLE", "LZW", "LOSSLESS", "JPEG", "DEFLATE"

// possible file types:
// "undefined", "TIFF", "VIFF", "JPEG", "PNG", "PNM", "BMP", "SUN", "XPM", "EXR"

// possible name extensions:
// "undefined", "tif", "tiff", "jpg", "jpeg", "png", "pnm", "bmp", "sun",
// "xpm", "exr" (also capital forms)

namespace vigra
{
    template <class T>
    struct TypeAsString
    {
        static std::string result() { return "undefined"; }
    };

    template <>
    struct TypeAsString<Int8>
    {
        static std::string result() { return "INT8"; }
    };

    template <>
    struct TypeAsString<UInt8>
    {
        static std::string result() { return "UINT8"; }
    };

    template <>
    struct TypeAsString<Int16>
    {
        static std::string result() { return "INT16"; }
    };

    template <>
    struct TypeAsString<UInt16>
    {
        static std::string result() { return "UINT16"; }
    };

    template <>
    struct TypeAsString<Int32>
    {
        static std::string result() { return "INT32"; }
    };

    template <>
    struct TypeAsString<UInt32>
    {
        static std::string result() { return "UINT32"; }
    };

    template <>
    struct TypeAsString<float>
    {
        static std::string result() { return "FLOAT"; }
    };

    template <>
    struct TypeAsString<double>
    {
        static std::string result() { return "DOUBLE"; }
    };

    // codec description
    struct CodecDesc
    {
        std::string fileType;
        std::vector<std::string> pixelTypes;
        std::vector<std::string> compressionTypes;
        std::vector<std::vector<char> > magicStrings;
        std::vector<std::string> fileExtensions;
        std::vector<int> bandNumbers;
    };

    // Decoder and Encoder are virtual types that define a common
    // interface for all image file formats impex supports.

    struct Decoder
    {
        virtual ~Decoder() {};
        virtual void init( const std::string & ) = 0;
        virtual void close() = 0;
        virtual void abort() = 0;

        virtual std::string getFileType() const = 0;
        virtual std::string getPixelType() const = 0;

        virtual unsigned int getWidth() const = 0;
        virtual unsigned int getHeight() const = 0;
        virtual unsigned int getNumBands() const = 0;
        virtual unsigned int getNumExtraBands() const
        {
            return 0;
        }

        virtual vigra::Diff2D getPosition() const
        {
            return vigra::Diff2D();
        }

        virtual float getXResolution() const
        {
            return 0.0f;
        }
        virtual float getYResolution() const
        {
            return 0.0f;
        }

        virtual vigra::Size2D getCanvasSize() const
        {
            return vigra::Size2D(this->getWidth(), this->getHeight());
        }

        virtual unsigned int getOffset() const = 0;

        virtual const void * currentScanlineOfBand( unsigned int ) const = 0;
        virtual void nextScanline() = 0;

        typedef ArrayVector<unsigned char> ICCProfile;

        const ICCProfile & getICCProfile() const
        {
            return iccProfile_;
        }

        ICCProfile iccProfile_;
    };

    struct Encoder
    {
        virtual ~Encoder() {};
        virtual void init( const std::string & ) = 0;
        virtual void close() = 0;
        virtual void abort() = 0;

        virtual std::string getFileType() const = 0;
        virtual unsigned int getOffset() const = 0;

        virtual void setWidth( unsigned int ) = 0;
        virtual void setHeight( unsigned int ) = 0;
        virtual void setNumBands( unsigned int ) = 0;
        virtual void setCompressionType( const std::string &, int = -1 ) = 0;
        virtual void setPixelType( const std::string & ) = 0;
        virtual void finalizeSettings() = 0;

        virtual void setPosition( const vigra::Diff2D & /*pos*/ )
        {
        }
        virtual void setCanvasSize( const vigra::Size2D & /*size*/)
        {
        }
        virtual void setXResolution( float /*xres*/ )
        {
        }
        virtual void setYResolution( float /*yres*/ )
        {
        }

        typedef ArrayVector<unsigned char> ICCProfile;

        virtual void setICCProfile(const ICCProfile & /* data */)
        {
        }

        virtual void * currentScanlineOfBand( unsigned int ) = 0;
        virtual void nextScanline() = 0;

        struct TIFFCompressionException {};
    };

    // codec factory for registration at the codec manager

    struct CodecFactory
    {
        virtual CodecDesc getCodecDesc() const = 0;
        virtual std::auto_ptr<Decoder> getDecoder() const = 0;
        virtual std::auto_ptr<Encoder> getEncoder() const = 0;
        virtual ~CodecFactory() {};
    };

    // factory functions to encapsulate the codec managers
    //
    // codecs are selected according to the following order:
    // - (if provided) the FileType
    // - (in case of decoders) the file's magic string
    // - the filename extension

    VIGRA_EXPORT std::auto_ptr<Decoder>
    getDecoder( const std::string &, const std::string & = "undefined" );

    VIGRA_EXPORT std::auto_ptr<Encoder>
    getEncoder( const std::string &, const std::string & = "undefined" );

    VIGRA_EXPORT std::string
    getEncoderType( const std::string &, const std::string & = "undefined" );

    // functions to query the capabilities of certain codecs

    VIGRA_EXPORT std::vector<std::string> queryCodecPixelTypes( const std::string & );

    VIGRA_EXPORT bool negotiatePixelType( std::string const & codecname,
                 std::string const & srcPixeltype, std::string & destPixeltype);

    VIGRA_EXPORT bool isPixelTypeSupported( const std::string &, const std::string & );

    VIGRA_EXPORT bool isBandNumberSupported( const std::string &, int bands );
}

#endif // VIGRA_CODEC_HXX
<|endoftext|>


<commit_before>// Check that ASan dumps the CPU registers on a SIGSEGV.

// RUN: %clangxx_asan %s -o %t
// RUN: not %run %t 2>&1 | FileCheck %s

#include <assert.h>
#include <stdio.h>

int main() {
  fprintf(stderr, "Hello\n");
  char *ptr;

  if (sizeof(void *) == 8)
    ptr = (char *)0x6666666666666666;
  else if (sizeof(void *) == 4)
    ptr = (char *)0x55555555;
  else
    assert(0 && "Your computer is weird.");

  char c = *ptr;  // BOOM
  // CHECK: ERROR: AddressSanitizer: {{SEGV|BUS}}
  // CHECK: Register values:
  // CHECK: {{0x55555555|0x6666666666666666}}
  fprintf(stderr, "World\n");
  return c;
}
<commit_msg>[asan] Make dump_registers.cc more stable<commit_after>// Check that ASan dumps the CPU registers on a SIGSEGV.

// RUN: %clangxx_asan %s -o %t
// RUN: not %run %t 2>&1 | FileCheck %s

#include <assert.h>
#include <stdio.h>
#include <sys/mman.h>

int main() {
  fprintf(stderr, "Hello\n");
  char *ptr;

  ptr = (char *)mmap(NULL, 0x10000, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
  assert(ptr && "failed to mmap");

  fprintf(stderr, sizeof(uintptr_t) == 8 ? "p = 0x%016lx\n" : "p = 0x%08lx\n", (uintptr_t)ptr);
  // CHECK: p = [[ADDR:0x[0-9]+]]

  char c = *ptr;  // BOOM
  // CHECK: ERROR: AddressSanitizer: {{SEGV|BUS}}
  // CHECK: Register values:
  // CHECK: [[ADDR]]
  fprintf(stderr, "World\n");
  return c;
}
<|endoftext|>


<commit_before>#include "Halide.h"

using namespace Halide;

int multi_type_test() {
    Func f1("f1"), f2("f2"), f3("f3"), f4("f4"), f5("f5"), f6("f6");
    Var x, y, z;

    f1(x, y, z) = cast<uint8_t>(1);
    f2(x, y, z) = cast<uint32_t>(f1(x+1, y, z) + f1(x, y+1, z));
    f3(x, y, z) = cast<uint16_t>(f2(x+1, y, z) + f2(x, y+1, z));
    f4(x, y, z) = cast<uint16_t>(f3(x+1, y, z) + f3(x, y+1, z));
    f5(x, y, z) = cast<uint32_t>(f4(x+1, y, z) + f4(x, y+1, z));
    f6(x, y, z) = cast<uint8_t>(f5(x+1, y, z) + f5(x, y+1, z));

    f6.compute_root().gpu_tile(x, y, 1, 1);
    f5.compute_at(f6, Var::gpu_blocks()).gpu_threads(x, y);
    f4.compute_at(f6, Var::gpu_blocks()).gpu_threads(x, y);
    f3.compute_at(f6, Var::gpu_blocks()).gpu_threads(x, y);
    f2.compute_at(f6, Var::gpu_blocks()).gpu_threads(x, y);
    f1.compute_at(f6, Var::gpu_blocks()).gpu_threads(x, y);

    const int size_x = 200;
    const int size_y = 200;
    const int size_z = 4;

    Image<uint8_t> out = f6.realize(size_x, size_y, size_z);

    uint8_t correct = 32;
    for (int z = 0; z < size_z; z++) {
        for (int y = 0; y < size_y; y++) {
            for (int x = 0; x < size_x; x++) {
                if (out(x, y, z) != correct) {
                    printf("out(%d, %d, %d) = %d instead of %d\n",
                           x, y, z, out(x, y, z), correct);
                    return -1;
                }
            }
        }
    }

    printf("Success!\n");
    return 0;
}

int pyramid_test() {
    const int levels = 10;
    const int size_x = 100;
    const int size_y = 100;

    Var x, y, z, xo, xi, yo, yi;

    std::vector<Func> funcs(levels);

    funcs[0](x, y) = 1;
    for (int i = 1; i < levels; ++i) {
        funcs[i](x, y) = funcs[i-1](2*x, y);
    }

    funcs[levels-1].compute_root().split(x, xo, xi, 4).split(y, yo, yi, 4).gpu_tile(xo, yo, 1, 1);
    for (int i = levels-2; i >= 0; --i) {
        funcs[i].compute_at(funcs[levels-1], Var::gpu_blocks()).split(x, xo, xi, 4).split(y, yo, yi, 4).gpu_threads(xo, yo);
    }

    Image<int> out = funcs[levels-1].realize(size_x, size_y);

    int correct = 1;
    for (int y = 0; y < size_y; y++) {
        for (int x = 0; x < size_x; x++) {
            if (out(x, y) != correct) {
                printf("out(%d, %d) = %d instead of %d\n",
                       x, y, out(x, y), correct);
                return -1;
            }
        }
    }

    printf("Success!\n");
    return 0;
}

int inverted_pyramid_test() {
    const int levels = 6;
    const int size_x = 100;
    const int size_y = 400;

    Var x, y, z, yo, yi;

    std::vector<Func> funcs(levels);

    funcs[0](x, y) = 1;
    for (int i = 1; i < levels; ++i) {
        int max_size = size_x/std::pow(2, levels-i) + 1;
        funcs[i](x, y) = funcs[i-1](x%max_size, y);
    }

    funcs[levels-1].compute_root().split(y, yo, yi, 19).gpu_tile(x, yo, 8, 8);
    for (int i = levels-2; i >= 0; --i) {
        funcs[i].compute_at(funcs[levels-1], Var::gpu_blocks()).split(y, yo, yi, 19).gpu_threads(x, yo);
    }

    Image<int> out = funcs[levels-1].realize(size_x, size_y);

    int correct = 1;
    for (int y = 0; y < size_y; y++) {
        for (int x = 0; x < size_x; x++) {
            if (out(x, y) != correct) {
                printf("out(%d, %d) = %d instead of %d\n",
                       x, y, out(x, y), correct);
                return -1;
            }
        }
    }

    printf("Success!\n");
    return 0;
}

int dynamic_shared_test() {
    if (!get_jit_target_from_environment().has_gpu_feature()) {
        printf("Not running test because no gpu target enabled\n");
        return 0;
    }

    Func f1, f2, f3, f4;
    Var x, xo, xi;

    f1(x) = x;
    f2(x) = f1(x) + f1(2*x);
    f3(x) = f2(x) + f2(2*x);
    f4(x) = f3(x) + f3(2*x);

    f4.split(x, xo, xi, 16).gpu_tile(xo, 16);
    f3.compute_at(f4, Var::gpu_blocks()).split(x, xo, xi, 16).gpu_threads(xo);
    f2.compute_at(f4, Var::gpu_blocks()).split(x, xo, xi, 16).gpu_threads(xo);
    f1.compute_at(f4, Var::gpu_blocks()).split(x, xo, xi, 16).gpu_threads(xo);

    // The amount of shared memory required varies with x

    Image<int> out = f4.realize(500);
    for (int x = 0; x < out.width(); x++) {
        int correct = 27*x;
        if (out(x) != correct) {
            printf("out(%d) = %d instead of %d\n",
                   x, out(x), correct);
            return -1;
        }
    }

    printf("Success!\n");
    return 0;
}

int main(int argc, char **argv) {
    if (!get_jit_target_from_environment().has_gpu_feature()) {
        printf("Not running test because no gpu target enabled\n");
        return 0;
    }

    printf("Running multi type test!\n");
    if (multi_type_test() != 0) {
        return -1;
    }

    printf("Running pyramid test!\n");
    if (pyramid_test() != 0) {
        return -1;
    }

    printf("Running inverted pyramid test!\n");
    if (inverted_pyramid_test() != 0) {
        return -1;
    }

    printf("Running dynamic shared test!\n");
    if (dynamic_shared_test() != 0) {
        return -1;
    }

    return 0;
}
<commit_msg>Use fewer gpu threads in shared mem reuse test<commit_after>#include "Halide.h"

using namespace Halide;

int multi_type_test() {
    Func f1("f1"), f2("f2"), f3("f3"), f4("f4"), f5("f5"), f6("f6");
    Var x, y, z;

    f1(x, y, z) = cast<uint8_t>(1);
    f2(x, y, z) = cast<uint32_t>(f1(x+1, y, z) + f1(x, y+1, z));
    f3(x, y, z) = cast<uint16_t>(f2(x+1, y, z) + f2(x, y+1, z));
    f4(x, y, z) = cast<uint16_t>(f3(x+1, y, z) + f3(x, y+1, z));
    f5(x, y, z) = cast<uint32_t>(f4(x+1, y, z) + f4(x, y+1, z));
    f6(x, y, z) = cast<uint8_t>(f5(x+1, y, z) + f5(x, y+1, z));

    f6.compute_root().gpu_tile(x, y, 1, 1);
    f5.compute_at(f6, Var::gpu_blocks()).gpu_threads(x, y);
    f4.compute_at(f6, Var::gpu_blocks()).gpu_threads(x, y);
    f3.compute_at(f6, Var::gpu_blocks()).gpu_threads(x, y);
    f2.compute_at(f6, Var::gpu_blocks()).gpu_threads(x, y);
    f1.compute_at(f6, Var::gpu_blocks()).gpu_threads(x, y);

    const int size_x = 200;
    const int size_y = 200;
    const int size_z = 4;

    Image<uint8_t> out = f6.realize(size_x, size_y, size_z);

    uint8_t correct = 32;
    for (int z = 0; z < size_z; z++) {
        for (int y = 0; y < size_y; y++) {
            for (int x = 0; x < size_x; x++) {
                if (out(x, y, z) != correct) {
                    printf("out(%d, %d, %d) = %d instead of %d\n",
                           x, y, z, out(x, y, z), correct);
                    return -1;
                }
            }
        }
    }

    printf("Success!\n");
    return 0;
}

int pyramid_test() {
    const int levels = 10;
    const int size_x = 100;
    const int size_y = 100;

    Var x, y, z, xo, xi, yo, yi;

    std::vector<Func> funcs(levels);

    funcs[0](x, y) = 1;
    for (int i = 1; i < levels; ++i) {
        funcs[i](x, y) = funcs[i-1](2*x, y);
    }

    funcs[levels-1].compute_root()
        .gpu_tile(x, y, 4, 4);
    for (int i = levels-2; i >= 0; --i) {
        funcs[i].compute_at(funcs[levels-1], Var::gpu_blocks())
            .split(x, xo, xi, 1 << (levels - i - 1))
            .gpu_threads(xo, y);
    }

    Image<int> out = funcs[levels-1].realize(size_x, size_y);

    int correct = 1;
    for (int y = 0; y < size_y; y++) {
        for (int x = 0; x < size_x; x++) {
            if (out(x, y) != correct) {
                printf("out(%d, %d) = %d instead of %d\n",
                       x, y, out(x, y), correct);
                return -1;
            }
        }
    }

    printf("Success!\n");
    return 0;
}

int inverted_pyramid_test() {
    const int levels = 6;
    const int size_x = 8*16;
    const int size_y = 8*16;

    Var x, y, z, yo, yi, xo, xi;

    std::vector<Func> funcs(levels);

    funcs[0](x, y) = 1;
    for (int i = 1; i < levels; ++i) {
        funcs[i](x, y) = funcs[i-1](x/2, y);
    }

    funcs[levels-1].compute_root()
        .tile(x, y, xo, yo, xi, yi, 16, 16)
        .gpu_tile(xo, yo, 8, 8);
    for (int i = levels-2; i >= 0; --i) {
        funcs[i].compute_at(funcs[levels-1], Var::gpu_blocks())
            .tile(x, y, xo, yo, xi, yi, 16, 16)
            .gpu_threads(xo, yo);
    }

    Image<int> out = funcs[levels-1].realize(size_x, size_y);

    int correct = 1;
    for (int y = 0; y < size_y; y++) {
        for (int x = 0; x < size_x; x++) {
            if (out(x, y) != correct) {
                printf("out(%d, %d) = %d instead of %d\n",
                       x, y, out(x, y), correct);
                return -1;
            }
        }
    }

    printf("Success!\n");
    return 0;
}

int dynamic_shared_test() {
    if (!get_jit_target_from_environment().has_gpu_feature()) {
        printf("Not running test because no gpu target enabled\n");
        return 0;
    }

    Func f1, f2, f3, f4;
    Var x, xo, xi;

    f1(x) = x;
    f2(x) = f1(x) + f1(2*x);
    f3(x) = f2(x) + f2(2*x);
    f4(x) = f3(x) + f3(2*x);

    f4.split(x, xo, xi, 16).gpu_tile(xo, 16);
    f3.compute_at(f4, Var::gpu_blocks()).split(x, xo, xi, 16).gpu_threads(xi);
    f2.compute_at(f4, Var::gpu_blocks()).split(x, xo, xi, 16).gpu_threads(xi);
    f1.compute_at(f4, Var::gpu_blocks()).split(x, xo, xi, 16).gpu_threads(xi);

    // The amount of shared memory required varies with x

    Image<int> out = f4.realize(500);
    for (int x = 0; x < out.width(); x++) {
        int correct = 27*x;
        if (out(x) != correct) {
            printf("out(%d) = %d instead of %d\n",
                   x, out(x), correct);
            return -1;
        }
    }

    printf("Success!\n");
    return 0;
}

int main(int argc, char **argv) {
    if (!get_jit_target_from_environment().has_gpu_feature()) {
        printf("Not running test because no gpu target enabled\n");
        return 0;
    }

    printf("Running multi type test!\n");
    if (multi_type_test() != 0) {
        return -1;
    }

    printf("Running pyramid test!\n");
    if (pyramid_test() != 0) {
        return -1;
    }

    printf("Running inverted pyramid test!\n");
    if (inverted_pyramid_test() != 0) {
        return -1;
    }

    printf("Running dynamic shared test!\n");
    if (dynamic_shared_test() != 0) {
        return -1;
    }

    return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ManifestExport.cxx,v $
 *
 *  $Revision: 1.14 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 17:22:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_package.hxx"

#ifndef _MANIFEST_EXPORT_HXX
#include <ManifestExport.hxx>
#endif
#ifndef _ATTRIBUTE_LIST_HXX
#include <AttributeList.hxx>
#endif
#ifndef _MANIFEST_DEFINES_HXX
#include <ManifestDefines.hxx>
#endif
#ifndef _COM_SUN_STAR_XML_SAX_XATTRIBUTELIST_HXX
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#endif
#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif
#ifndef _BASE64_CODEC_HXX_
#include <Base64Codec.hxx>
#endif
#ifndef _COM_SUN_STAR_XML_SAX_XEXTENDEDDOCUMENTHANDLER_HPP_
#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
#endif
#ifndef _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HXX
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#endif
#ifndef _COM_SUN_STAR_XML_BEANS_PROPERTYVALUE_HPP
#include <com/sun/star/beans/PropertyValue.hpp>
#endif

#include <comphelper/documentconstants.hxx>

using namespace rtl;
using namespace com::sun::star::beans;
using namespace com::sun::star::uno;
using namespace com::sun::star::xml::sax;

ManifestExport::ManifestExport(Reference < XDocumentHandler > xHandler,  const Sequence < Sequence < PropertyValue > > &rManList )
{
    const OUString sFileEntryElement    ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_FILE_ENTRY ) );
    const OUString sManifestElement     ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_MANIFEST ) );
    const OUString sEncryptionDataElement( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_ENCRYPTION_DATA ) );
    const OUString sAlgorithmElement    ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_ALGORITHM ) );
    const OUString sKeyDerivationElement( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_KEY_DERIVATION ) );

    const OUString sCdataAttribute      ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CDATA ) );
    const OUString sMediaTypeAttribute  ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_MEDIA_TYPE ) );
    const OUString sFullPathAttribute   ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_FULL_PATH ) );
    const OUString sSizeAttribute       ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SIZE ) );
    const OUString sSaltAttribute       ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SALT ) );
    const OUString sInitialisationVectorAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_INITIALISATION_VECTOR ) );
    const OUString sIterationCountAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ITERATION_COUNT ) );
    const OUString sAlgorithmNameAttribute  ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ALGORITHM_NAME ) );
    const OUString sKeyDerivationNameAttribute  ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_KEY_DERIVATION_NAME ) );
    const OUString sChecksumTypeAttribute   ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM_TYPE ) );
    const OUString sChecksumAttribute   ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM) );

    const OUString sFullPathProperty    ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
    const OUString sMediaTypeProperty   ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
    const OUString sIterationCountProperty  ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) );
    const OUString sSaltProperty        ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) );
    const OUString sInitialisationVectorProperty( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) );
    const OUString sSizeProperty        ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) );
    const OUString sDigestProperty      ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) );

    const OUString sWhiteSpace          ( RTL_CONSTASCII_USTRINGPARAM ( " " ) );
    const OUString sBlowfish            ( RTL_CONSTASCII_USTRINGPARAM ( "Blowfish CFB" ) );
    const OUString sPBKDF2              ( RTL_CONSTASCII_USTRINGPARAM ( "PBKDF2" ) );
    const OUString sChecksumType        ( RTL_CONSTASCII_USTRINGPARAM ( CHECKSUM_TYPE ) );

    AttributeList * pRootAttrList = new AttributeList;
    const Sequence < PropertyValue > *pSequence = rManList.getConstArray();
    const sal_uInt32 nManLength = rManList.getLength();

    // find the mediatype of the document if any
    OUString aDocMediaType;
    for (sal_uInt32 nInd = 0; nInd < nManLength ; nInd++ )
    {
        OUString aMediaType;
        OUString aPath;

        const PropertyValue *pValue = pSequence[nInd].getConstArray();
        for (sal_uInt32 j = 0, nNum = pSequence[nInd].getLength(); j < nNum; j++, pValue++)
        {

            if (pValue->Name.equals (sMediaTypeProperty) )
            {
                pValue->Value >>= aMediaType;
            }
            else if (pValue->Name.equals (sFullPathProperty) )
            {
                pValue->Value >>= aPath;
            }

            if ( aPath.getLength() && aMediaType.getLength() )
                break;
        }

        if ( aPath.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) ) )
        {
            aDocMediaType = aMediaType;
            break;
        }
    }

    sal_Bool bProvideDTD = sal_False;
    if ( aDocMediaType.getLength() )
    {
        if ( aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII ) ) )

          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII ) ) ) )

        {
            // oasis format
            pRootAttrList->AddAttribute ( OUString( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_XMLNS ) ),
                                        sCdataAttribute,
                                        OUString( RTL_CONSTASCII_USTRINGPARAM ( MANIFEST_OASIS_NAMESPACE ) ) );
        }
        else
        {
            // even if it is no SO6 format the namespace must be specified
            // thus SO6 format is used as default one
            pRootAttrList->AddAttribute ( OUString( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_XMLNS ) ),
                                        sCdataAttribute,
                                        OUString( RTL_CONSTASCII_USTRINGPARAM ( MANIFEST_NAMESPACE ) ) );

            bProvideDTD = sal_True;
        }
    }

    Reference < XAttributeList > xRootAttrList (pRootAttrList);

    xHandler->startDocument();
    Reference < XExtendedDocumentHandler > xExtHandler ( xHandler, UNO_QUERY );
    if ( xExtHandler.is() && bProvideDTD )
    {
        OUString aDocType ( RTL_CONSTASCII_USTRINGPARAM ( MANIFEST_DOCTYPE ) );
        xExtHandler->unknown ( aDocType );
        xHandler->ignorableWhitespace ( sWhiteSpace );
    }
    xHandler->startElement( sManifestElement, xRootAttrList );

    for (sal_uInt32 i = 0 ; i < nManLength ; i++)
    {
        AttributeList *pAttrList = new AttributeList;
        const PropertyValue *pValue = pSequence[i].getConstArray();
        OUString aString;
        const PropertyValue *pVector = NULL, *pSalt = NULL, *pIterationCount = NULL, *pDigest = NULL;
        for (sal_uInt32 j = 0, nNum = pSequence[i].getLength(); j < nNum; j++, pValue++)
        {
            if (pValue->Name.equals (sMediaTypeProperty) )
            {
                pValue->Value >>= aString;
                pAttrList->AddAttribute ( sMediaTypeAttribute, sCdataAttribute, aString );
            }
            else if (pValue->Name.equals (sFullPathProperty) )
            {
                pValue->Value >>= aString;
                pAttrList->AddAttribute ( sFullPathAttribute, sCdataAttribute, aString );
            }
            else if (pValue->Name.equals (sSizeProperty) )
            {
                sal_Int32 nSize;
                pValue->Value >>= nSize;
                OUStringBuffer aBuffer;
                aBuffer.append ( nSize );
                pAttrList->AddAttribute ( sSizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
            }
            else if (pValue->Name.equals (sInitialisationVectorProperty) )
                pVector = pValue;
            else if (pValue->Name.equals (sSaltProperty) )
                pSalt = pValue;
            else if (pValue->Name.equals (sIterationCountProperty) )
                pIterationCount = pValue;
            else if (pValue->Name.equals ( sDigestProperty ) )
                pDigest = pValue;
        }
        xHandler->ignorableWhitespace ( sWhiteSpace );
        Reference < XAttributeList > xAttrList ( pAttrList );
        xHandler->startElement( sFileEntryElement , xAttrList);
        if ( pVector && pSalt && pIterationCount )
        {
            AttributeList * pNewAttrList = new AttributeList;
            Reference < XAttributeList > xNewAttrList (pNewAttrList);
            OUStringBuffer aBuffer;
            Sequence < sal_uInt8 > aSequence;

            xHandler->ignorableWhitespace ( sWhiteSpace );
            if ( pDigest )
            {
                pNewAttrList->AddAttribute ( sChecksumTypeAttribute, sCdataAttribute, sChecksumType );
                pDigest->Value >>= aSequence;
                Base64Codec::encodeBase64 ( aBuffer, aSequence );
                pNewAttrList->AddAttribute ( sChecksumAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
            }
            xHandler->startElement( sEncryptionDataElement , xNewAttrList);

            pNewAttrList = new AttributeList;
            xNewAttrList = pNewAttrList;

            pNewAttrList->AddAttribute ( sAlgorithmNameAttribute, sCdataAttribute, sBlowfish );

            pVector->Value >>= aSequence;
            Base64Codec::encodeBase64 ( aBuffer, aSequence );
            pNewAttrList->AddAttribute ( sInitialisationVectorAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );

            xHandler->ignorableWhitespace ( sWhiteSpace );
            xHandler->startElement( sAlgorithmElement , xNewAttrList);
            xHandler->ignorableWhitespace ( sWhiteSpace );
            xHandler->endElement( sAlgorithmElement );

            pNewAttrList = new AttributeList;
            xNewAttrList = pNewAttrList;

            pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute, sCdataAttribute, sPBKDF2 );

            sal_Int32 nCount;
            pIterationCount->Value >>= nCount;
            aBuffer.append (nCount);
            pNewAttrList->AddAttribute ( sIterationCountAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );

            pSalt->Value >>= aSequence;
            Base64Codec::encodeBase64 ( aBuffer, aSequence );
            pNewAttrList->AddAttribute ( sSaltAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );

            xHandler->ignorableWhitespace ( sWhiteSpace );
            xHandler->startElement( sKeyDerivationElement , xNewAttrList);
            xHandler->ignorableWhitespace ( sWhiteSpace );
            xHandler->endElement( sKeyDerivationElement );
            xHandler->ignorableWhitespace ( sWhiteSpace );
            xHandler->endElement( sEncryptionDataElement );
        }
        xHandler->ignorableWhitespace ( sWhiteSpace );
        xHandler->endElement( sFileEntryElement );
    }
    xHandler->ignorableWhitespace ( sWhiteSpace );
    xHandler->endElement( sManifestElement );
    xHandler->endDocument();
}
<commit_msg>INTEGRATION: CWS opofxmlstorage (1.12.10); FILE MERGED 2006/06/29 15:44:05 mav 1.12.10.2: RESYNC: (1.12-1.13); FILE MERGED 2006/04/21 11:36:58 mav 1.12.10.1: #i64612# support OFOPXML format<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ManifestExport.cxx,v $
 *
 *  $Revision: 1.15 $
 *
 *  last change: $Author: obo $ $Date: 2006-10-13 11:47:36 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_package.hxx"

#ifndef _MANIFEST_EXPORT_HXX
#include <ManifestExport.hxx>
#endif
#ifndef _MANIFEST_DEFINES_HXX
#include <ManifestDefines.hxx>
#endif
#ifndef _COM_SUN_STAR_XML_SAX_XATTRIBUTELIST_HXX
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#endif
#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif
#ifndef _BASE64_CODEC_HXX_
#include <Base64Codec.hxx>
#endif
#ifndef _COM_SUN_STAR_XML_SAX_XEXTENDEDDOCUMENTHANDLER_HPP_
#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
#endif
#ifndef _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HXX
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#endif
#ifndef _COM_SUN_STAR_XML_BEANS_PROPERTYVALUE_HPP
#include <com/sun/star/beans/PropertyValue.hpp>
#endif

#include <comphelper/documentconstants.hxx>
#include <comphelper/attributelist.hxx>

using namespace rtl;
using namespace com::sun::star::beans;
using namespace com::sun::star::uno;
using namespace com::sun::star::xml::sax;

ManifestExport::ManifestExport(Reference < XDocumentHandler > xHandler,  const Sequence < Sequence < PropertyValue > > &rManList )
{
    const OUString sFileEntryElement    ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_FILE_ENTRY ) );
    const OUString sManifestElement     ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_MANIFEST ) );
    const OUString sEncryptionDataElement( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_ENCRYPTION_DATA ) );
    const OUString sAlgorithmElement    ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_ALGORITHM ) );
    const OUString sKeyDerivationElement( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_KEY_DERIVATION ) );

    const OUString sCdataAttribute      ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CDATA ) );
    const OUString sMediaTypeAttribute  ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_MEDIA_TYPE ) );
    const OUString sFullPathAttribute   ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_FULL_PATH ) );
    const OUString sSizeAttribute       ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SIZE ) );
    const OUString sSaltAttribute       ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SALT ) );
    const OUString sInitialisationVectorAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_INITIALISATION_VECTOR ) );
    const OUString sIterationCountAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ITERATION_COUNT ) );
    const OUString sAlgorithmNameAttribute  ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ALGORITHM_NAME ) );
    const OUString sKeyDerivationNameAttribute  ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_KEY_DERIVATION_NAME ) );
    const OUString sChecksumTypeAttribute   ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM_TYPE ) );
    const OUString sChecksumAttribute   ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM) );

    const OUString sFullPathProperty    ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
    const OUString sMediaTypeProperty   ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
    const OUString sIterationCountProperty  ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) );
    const OUString sSaltProperty        ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) );
    const OUString sInitialisationVectorProperty( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) );
    const OUString sSizeProperty        ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) );
    const OUString sDigestProperty      ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) );

    const OUString sWhiteSpace          ( RTL_CONSTASCII_USTRINGPARAM ( " " ) );
    const OUString sBlowfish            ( RTL_CONSTASCII_USTRINGPARAM ( "Blowfish CFB" ) );
    const OUString sPBKDF2              ( RTL_CONSTASCII_USTRINGPARAM ( "PBKDF2" ) );
    const OUString sChecksumType        ( RTL_CONSTASCII_USTRINGPARAM ( CHECKSUM_TYPE ) );

    ::comphelper::AttributeList * pRootAttrList = new ::comphelper::AttributeList;
    const Sequence < PropertyValue > *pSequence = rManList.getConstArray();
    const sal_uInt32 nManLength = rManList.getLength();

    // find the mediatype of the document if any
    OUString aDocMediaType;
    for (sal_uInt32 nInd = 0; nInd < nManLength ; nInd++ )
    {
        OUString aMediaType;
        OUString aPath;

        const PropertyValue *pValue = pSequence[nInd].getConstArray();
        for (sal_uInt32 j = 0, nNum = pSequence[nInd].getLength(); j < nNum; j++, pValue++)
        {

            if (pValue->Name.equals (sMediaTypeProperty) )
            {
                pValue->Value >>= aMediaType;
            }
            else if (pValue->Name.equals (sFullPathProperty) )
            {
                pValue->Value >>= aPath;
            }

            if ( aPath.getLength() && aMediaType.getLength() )
                break;
        }

        if ( aPath.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) ) )
        {
            aDocMediaType = aMediaType;
            break;
        }
    }

    sal_Bool bProvideDTD = sal_False;
    if ( aDocMediaType.getLength() )
    {
        if ( aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII ) ) )

          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII ) ) )
          || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII ) ) ) )

        {
            // oasis format
            pRootAttrList->AddAttribute ( OUString( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_XMLNS ) ),
                                        sCdataAttribute,
                                        OUString( RTL_CONSTASCII_USTRINGPARAM ( MANIFEST_OASIS_NAMESPACE ) ) );
        }
        else
        {
            // even if it is no SO6 format the namespace must be specified
            // thus SO6 format is used as default one
            pRootAttrList->AddAttribute ( OUString( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_XMLNS ) ),
                                        sCdataAttribute,
                                        OUString( RTL_CONSTASCII_USTRINGPARAM ( MANIFEST_NAMESPACE ) ) );

            bProvideDTD = sal_True;
        }
    }

    Reference < XAttributeList > xRootAttrList (pRootAttrList);

    xHandler->startDocument();
    Reference < XExtendedDocumentHandler > xExtHandler ( xHandler, UNO_QUERY );
    if ( xExtHandler.is() && bProvideDTD )
    {
        OUString aDocType ( RTL_CONSTASCII_USTRINGPARAM ( MANIFEST_DOCTYPE ) );
        xExtHandler->unknown ( aDocType );
        xHandler->ignorableWhitespace ( sWhiteSpace );
    }
    xHandler->startElement( sManifestElement, xRootAttrList );

    for (sal_uInt32 i = 0 ; i < nManLength ; i++)
    {
        ::comphelper::AttributeList *pAttrList = new ::comphelper::AttributeList;
        const PropertyValue *pValue = pSequence[i].getConstArray();
        OUString aString;
        const PropertyValue *pVector = NULL, *pSalt = NULL, *pIterationCount = NULL, *pDigest = NULL;
        for (sal_uInt32 j = 0, nNum = pSequence[i].getLength(); j < nNum; j++, pValue++)
        {
            if (pValue->Name.equals (sMediaTypeProperty) )
            {
                pValue->Value >>= aString;
                pAttrList->AddAttribute ( sMediaTypeAttribute, sCdataAttribute, aString );
            }
            else if (pValue->Name.equals (sFullPathProperty) )
            {
                pValue->Value >>= aString;
                pAttrList->AddAttribute ( sFullPathAttribute, sCdataAttribute, aString );
            }
            else if (pValue->Name.equals (sSizeProperty) )
            {
                sal_Int32 nSize;
                pValue->Value >>= nSize;
                OUStringBuffer aBuffer;
                aBuffer.append ( nSize );
                pAttrList->AddAttribute ( sSizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
            }
            else if (pValue->Name.equals (sInitialisationVectorProperty) )
                pVector = pValue;
            else if (pValue->Name.equals (sSaltProperty) )
                pSalt = pValue;
            else if (pValue->Name.equals (sIterationCountProperty) )
                pIterationCount = pValue;
            else if (pValue->Name.equals ( sDigestProperty ) )
                pDigest = pValue;
        }
        xHandler->ignorableWhitespace ( sWhiteSpace );
        Reference < XAttributeList > xAttrList ( pAttrList );
        xHandler->startElement( sFileEntryElement , xAttrList);
        if ( pVector && pSalt && pIterationCount )
        {
            ::comphelper::AttributeList * pNewAttrList = new ::comphelper::AttributeList;
            Reference < XAttributeList > xNewAttrList (pNewAttrList);
            OUStringBuffer aBuffer;
            Sequence < sal_uInt8 > aSequence;

            xHandler->ignorableWhitespace ( sWhiteSpace );
            if ( pDigest )
            {
                pNewAttrList->AddAttribute ( sChecksumTypeAttribute, sCdataAttribute, sChecksumType );
                pDigest->Value >>= aSequence;
                Base64Codec::encodeBase64 ( aBuffer, aSequence );
                pNewAttrList->AddAttribute ( sChecksumAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
            }
            xHandler->startElement( sEncryptionDataElement , xNewAttrList);

            pNewAttrList = new ::comphelper::AttributeList;
            xNewAttrList = pNewAttrList;

            pNewAttrList->AddAttribute ( sAlgorithmNameAttribute, sCdataAttribute, sBlowfish );

            pVector->Value >>= aSequence;
            Base64Codec::encodeBase64 ( aBuffer, aSequence );
            pNewAttrList->AddAttribute ( sInitialisationVectorAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );

            xHandler->ignorableWhitespace ( sWhiteSpace );
            xHandler->startElement( sAlgorithmElement , xNewAttrList);
            xHandler->ignorableWhitespace ( sWhiteSpace );
            xHandler->endElement( sAlgorithmElement );

            pNewAttrList = new ::comphelper::AttributeList;
            xNewAttrList = pNewAttrList;

            pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute, sCdataAttribute, sPBKDF2 );

            sal_Int32 nCount;
            pIterationCount->Value >>= nCount;
            aBuffer.append (nCount);
            pNewAttrList->AddAttribute ( sIterationCountAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );

            pSalt->Value >>= aSequence;
            Base64Codec::encodeBase64 ( aBuffer, aSequence );
            pNewAttrList->AddAttribute ( sSaltAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );

            xHandler->ignorableWhitespace ( sWhiteSpace );
            xHandler->startElement( sKeyDerivationElement , xNewAttrList);
            xHandler->ignorableWhitespace ( sWhiteSpace );
            xHandler->endElement( sKeyDerivationElement );
            xHandler->ignorableWhitespace ( sWhiteSpace );
            xHandler->endElement( sEncryptionDataElement );
        }
        xHandler->ignorableWhitespace ( sWhiteSpace );
        xHandler->endElement( sFileEntryElement );
    }
    xHandler->ignorableWhitespace ( sWhiteSpace );
    xHandler->endElement( sManifestElement );
    xHandler->endDocument();
}
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <cstdint>
#include <vector>

#include "caf/detail/comparable.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/detail/unordered_flat_map.hpp"
#include "caf/fwd.hpp"
#include "caf/hash/fnv.hpp"
#include "caf/inspector_access.hpp"
#include "caf/intrusive_cow_ptr.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/ip_address.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"

namespace caf {

/// A URI according to RFC 3986.
class CAF_CORE_EXPORT uri : detail::comparable<uri>,
                            detail::comparable<uri, string_view> {
public:
  // -- friends -

  template <class>
  friend struct inspector_access;

  // -- member types -----------------------------------------------------------

  /// Host subcomponent of the authority component. Either an IP address or
  /// an hostname as string.
  using host_type = variant<std::string, ip_address>;

  /// Bundles the authority component of the URI, i.e., userinfo, host, and
  /// port.
  struct authority_type {
    std::string userinfo;
    host_type host;
    uint16_t port;

    authority_type() : port(0) {
      // nop
    }

    /// Returns whether `host` is empty, i.e., the host is not an IP address
    /// and the string is empty.
    bool empty() const noexcept {
      auto str = get_if<std::string>(&host);
      return str != nullptr && str->empty();
    }
  };

  /// Separates the query component into key-value pairs.
  using path_list = std::vector<string_view>;

  /// Separates the query component into key-value pairs.
  using query_map = detail::unordered_flat_map<std::string, std::string>;

  class CAF_CORE_EXPORT impl_type {
  public:
    // -- constructors, destructors, and assignment operators ------------------

    impl_type();

    impl_type(const impl_type&) = delete;

    impl_type& operator=(const impl_type&) = delete;

    // -- member variables -----------------------------------------------------

    /// Null-terminated buffer for holding the string-representation of the URI.
    std::string str;

    /// Scheme component.
    std::string scheme;

    /// Assembled authority component.
    uri::authority_type authority;

    /// Path component.
    std::string path;

    /// Query component as key-value pairs.
    uri::query_map query;

    /// The fragment component.
    std::string fragment;

    // -- properties -----------------------------------------------------------

    bool valid() const noexcept {
      return !scheme.empty() && (!authority.empty() || !path.empty());
    }

    bool unique() const noexcept {
      return rc_.load() == 1;
    }

    // -- modifiers ------------------------------------------------------------

    /// Assembles the human-readable string representation for this URI.
    void assemble_str();

    // -- friend functions -----------------------------------------------------

    friend void intrusive_ptr_add_ref(const impl_type* p) {
      p->rc_.fetch_add(1, std::memory_order_relaxed);
    }

    friend void intrusive_ptr_release(const impl_type* p) {
      if (p->rc_ == 1 || p->rc_.fetch_sub(1, std::memory_order_acq_rel) == 1)
        delete p;
    }

  private:
    // -- member variables -----------------------------------------------------

    mutable std::atomic<size_t> rc_;
  };

  /// Pointer to implementation.
  using impl_ptr = intrusive_ptr<impl_type>;

  // -- constructors, destructors, and assignment operators --------------------

  uri();

  uri(uri&&) = default;

  uri(const uri&) = default;

  uri& operator=(uri&&) = default;

  uri& operator=(const uri&) = default;

  explicit uri(impl_ptr ptr);

  // -- properties -------------------------------------------------------------

  /// Returns whether all components of this URI are empty.
  bool empty() const noexcept {
    return str().empty();
  }

  /// Returns whether the URI contains valid content.
  bool valid() const noexcept {
    return !empty();
  }

  /// Returns the full URI as provided by the user.
  string_view str() const noexcept {
    return impl_->str;
  }

  /// Returns the scheme component.
  string_view scheme() const noexcept {
    return impl_->scheme;
  }

  /// Returns the authority component.
  const authority_type& authority() const noexcept {
    return impl_->authority;
  }

  /// Returns the path component as provided by the user.
  string_view path() const noexcept {
    return impl_->path;
  }

  /// Returns the query component as key-value map.
  const query_map& query() const noexcept {
    return impl_->query;
  }

  /// Returns the fragment component.
  string_view fragment() const noexcept {
    return impl_->fragment;
  }

  /// Returns a hash code over all components.
  size_t hash_code() const noexcept;

  /// Returns a new URI with the `authority` component only.
  /// @returns A new URI in the form `scheme://authority` if the authority
  ///          exists, otherwise `none`.`
  optional<uri> authority_only() const;

  // -- comparison -------------------------------------------------------------

  auto compare(const uri& other) const noexcept {
    return str().compare(other.str());
  }

  auto compare(string_view x) const noexcept {
    return str().compare(x);
  }

  // -- parsing ----------------------------------------------------------------

  /// Returns whether `parse` would produce a valid URI.
  static bool can_parse(string_view str) noexcept;

private:
  impl_ptr impl_;
};

// -- related free functions ---------------------------------------------------

template <class Inspector>
bool inspect(Inspector& f, uri::authority_type& x) {
  return f.object(x).fields(f.field("userinfo", x.userinfo),
                            f.field("host", x.host), f.field("port", x.port));
}

template <class Inspector>
bool inspect(Inspector& f, uri::impl_type& x) {
  auto load_cb = [&] {
    x.assemble_str();
    return true;
  };
  return f.object(x)
    .on_load(load_cb) //
    .fields(f.field("str", x.str), f.field("scheme", x.scheme),
            f.field("authority", x.authority), f.field("path", x.path),
            f.field("query", x.query), f.field("fragment", x.fragment));
}

/// @relates uri
CAF_CORE_EXPORT std::string to_string(const uri& x);

/// @relates uri
CAF_CORE_EXPORT std::string to_string(const uri::authority_type& x);

/// @relates uri
CAF_CORE_EXPORT error parse(string_view str, uri& dest);

/// @relates uri
CAF_CORE_EXPORT expected<uri> make_uri(string_view str);

template <>
struct inspector_access<uri> : inspector_access_base<uri> {
  template <class Inspector>
  static bool apply_object(Inspector& f, uri& x) {
    if (f.has_human_readable_format()) {
      // TODO: extend the inspector DSL to promote string_view to std::string
      //       automatically to avoid unnecessary to_string conversions.
      auto get = [&x] { return to_string(x); };
      // TODO: setters should be able to return the error directly to avoid loss
      //       of information.
      auto set = [&x](std::string str) {
        auto err = parse(str, x);
        return err.empty();
      };
      return f.object(x).fields(f.field("value", get, set));
    } else {
      if constexpr (Inspector::is_loading)
        if (!x.impl_->unique())
          x.impl_.reset(new uri::impl_type);
      return inspect(f, *x.impl_);
    }
  }

  template <class Inspector>
  static bool apply_value(Inspector& f, uri& x) {
    if (f.has_human_readable_format()) {
      auto get = [&x] { return to_string(x); };
      auto set = [&x](std::string str) {
        auto err = parse(str, x);
        return err.empty();
      };
      return detail::split_save_load(f, get, set);
    } else {
      if constexpr (Inspector::is_loading)
        if (!x.impl_->unique())
          x.impl_.reset(new uri::impl_type);
      return inspect(f, *x.impl_);
    }
  }
};

} // namespace caf

namespace std {

template <>
struct hash<caf::uri> {
  size_t operator()(const caf::uri& x) const noexcept {
    return caf::hash::fnv<size_t>::compute(x);
  }
};

} // namespace std
<commit_msg>Address leak warning in uri<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <cstdint>
#include <vector>

#include "caf/detail/comparable.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/detail/unordered_flat_map.hpp"
#include "caf/fwd.hpp"
#include "caf/hash/fnv.hpp"
#include "caf/inspector_access.hpp"
#include "caf/intrusive_cow_ptr.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/ip_address.hpp"
#include "caf/make_counted.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"

namespace caf {

/// A URI according to RFC 3986.
class CAF_CORE_EXPORT uri : detail::comparable<uri>,
                            detail::comparable<uri, string_view> {
public:
  // -- friends -

  template <class>
  friend struct inspector_access;

  // -- member types -----------------------------------------------------------

  /// Host subcomponent of the authority component. Either an IP address or
  /// an hostname as string.
  using host_type = variant<std::string, ip_address>;

  /// Bundles the authority component of the URI, i.e., userinfo, host, and
  /// port.
  struct authority_type {
    std::string userinfo;
    host_type host;
    uint16_t port;

    authority_type() : port(0) {
      // nop
    }

    /// Returns whether `host` is empty, i.e., the host is not an IP address
    /// and the string is empty.
    bool empty() const noexcept {
      auto str = get_if<std::string>(&host);
      return str != nullptr && str->empty();
    }
  };

  /// Separates the query component into key-value pairs.
  using path_list = std::vector<string_view>;

  /// Separates the query component into key-value pairs.
  using query_map = detail::unordered_flat_map<std::string, std::string>;

  class CAF_CORE_EXPORT impl_type {
  public:
    // -- constructors, destructors, and assignment operators ------------------

    impl_type();

    impl_type(const impl_type&) = delete;

    impl_type& operator=(const impl_type&) = delete;

    // -- member variables -----------------------------------------------------

    /// Null-terminated buffer for holding the string-representation of the URI.
    std::string str;

    /// Scheme component.
    std::string scheme;

    /// Assembled authority component.
    uri::authority_type authority;

    /// Path component.
    std::string path;

    /// Query component as key-value pairs.
    uri::query_map query;

    /// The fragment component.
    std::string fragment;

    // -- properties -----------------------------------------------------------

    bool valid() const noexcept {
      return !scheme.empty() && (!authority.empty() || !path.empty());
    }

    bool unique() const noexcept {
      return rc_.load() == 1;
    }

    // -- modifiers ------------------------------------------------------------

    /// Assembles the human-readable string representation for this URI.
    void assemble_str();

    // -- friend functions -----------------------------------------------------

    friend void intrusive_ptr_add_ref(const impl_type* p) {
      p->rc_.fetch_add(1, std::memory_order_relaxed);
    }

    friend void intrusive_ptr_release(const impl_type* p) {
      if (p->rc_ == 1 || p->rc_.fetch_sub(1, std::memory_order_acq_rel) == 1)
        delete p;
    }

  private:
    // -- member variables -----------------------------------------------------

    mutable std::atomic<size_t> rc_;
  };

  /// Pointer to implementation.
  using impl_ptr = intrusive_ptr<impl_type>;

  // -- constructors, destructors, and assignment operators --------------------

  uri();

  uri(uri&&) = default;

  uri(const uri&) = default;

  uri& operator=(uri&&) = default;

  uri& operator=(const uri&) = default;

  explicit uri(impl_ptr ptr);

  // -- properties -------------------------------------------------------------

  /// Returns whether all components of this URI are empty.
  bool empty() const noexcept {
    return str().empty();
  }

  /// Returns whether the URI contains valid content.
  bool valid() const noexcept {
    return !empty();
  }

  /// Returns the full URI as provided by the user.
  string_view str() const noexcept {
    return impl_->str;
  }

  /// Returns the scheme component.
  string_view scheme() const noexcept {
    return impl_->scheme;
  }

  /// Returns the authority component.
  const authority_type& authority() const noexcept {
    return impl_->authority;
  }

  /// Returns the path component as provided by the user.
  string_view path() const noexcept {
    return impl_->path;
  }

  /// Returns the query component as key-value map.
  const query_map& query() const noexcept {
    return impl_->query;
  }

  /// Returns the fragment component.
  string_view fragment() const noexcept {
    return impl_->fragment;
  }

  /// Returns a hash code over all components.
  size_t hash_code() const noexcept;

  /// Returns a new URI with the `authority` component only.
  /// @returns A new URI in the form `scheme://authority` if the authority
  ///          exists, otherwise `none`.`
  optional<uri> authority_only() const;

  // -- comparison -------------------------------------------------------------

  auto compare(const uri& other) const noexcept {
    return str().compare(other.str());
  }

  auto compare(string_view x) const noexcept {
    return str().compare(x);
  }

  // -- parsing ----------------------------------------------------------------

  /// Returns whether `parse` would produce a valid URI.
  static bool can_parse(string_view str) noexcept;

private:
  impl_ptr impl_;
};

// -- related free functions ---------------------------------------------------

template <class Inspector>
bool inspect(Inspector& f, uri::authority_type& x) {
  return f.object(x).fields(f.field("userinfo", x.userinfo),
                            f.field("host", x.host), f.field("port", x.port));
}

template <class Inspector>
bool inspect(Inspector& f, uri::impl_type& x) {
  auto load_cb = [&] {
    x.assemble_str();
    return true;
  };
  return f.object(x)
    .on_load(load_cb) //
    .fields(f.field("str", x.str), f.field("scheme", x.scheme),
            f.field("authority", x.authority), f.field("path", x.path),
            f.field("query", x.query), f.field("fragment", x.fragment));
}

/// @relates uri
CAF_CORE_EXPORT std::string to_string(const uri& x);

/// @relates uri
CAF_CORE_EXPORT std::string to_string(const uri::authority_type& x);

/// @relates uri
CAF_CORE_EXPORT error parse(string_view str, uri& dest);

/// @relates uri
CAF_CORE_EXPORT expected<uri> make_uri(string_view str);

template <>
struct inspector_access<uri> : inspector_access_base<uri> {
  template <class Inspector>
  static bool apply_object(Inspector& f, uri& x) {
    if (f.has_human_readable_format()) {
      // TODO: extend the inspector DSL to promote string_view to std::string
      //       automatically to avoid unnecessary to_string conversions.
      auto get = [&x] { return to_string(x); };
      // TODO: setters should be able to return the error directly to avoid loss
      //       of information.
      auto set = [&x](std::string str) {
        auto err = parse(str, x);
        return err.empty();
      };
      return f.object(x).fields(f.field("value", get, set));
    } else {
      if constexpr (Inspector::is_loading)
        if (!x.impl_->unique()) {
          x.impl_.reset();
          x.impl_ = make_counted<uri::impl_type>();
        }
      return inspect(f, *x.impl_);
    }
  }

  template <class Inspector>
  static bool apply_value(Inspector& f, uri& x) {
    if (f.has_human_readable_format()) {
      auto get = [&x] { return to_string(x); };
      auto set = [&x](std::string str) {
        auto err = parse(str, x);
        return err.empty();
      };
      return detail::split_save_load(f, get, set);
    } else {
      if constexpr (Inspector::is_loading)
        if (!x.impl_->unique()){
          x.impl_.reset();
          x.impl_ = make_counted<uri::impl_type>();
        }
      return inspect(f, *x.impl_);
    }
  }
};

} // namespace caf

namespace std {

template <>
struct hash<caf::uri> {
  size_t operator()(const caf::uri& x) const noexcept {
    return caf::hash::fnv<size_t>::compute(x);
  }
};

} // namespace std
<|endoftext|>


<commit_before>#include "Precompiled.h"
#include "Element.h"
#include "ElementManager.h"

namespace libgui
{
	// Element Manager
	void Element::SetElementManager(shared_ptr<ElementManager> elementManager)
	{
		m_elementManager = elementManager;
	}

	shared_ptr<ElementManager> Element::GetElementManager()
	{
		return m_elementManager;
	}

	// View Model
	void Element::SetViewModel(shared_ptr<ViewModelBase> viewModel)
	{
		m_viewModel = viewModel;
	}

	shared_ptr<ViewModelBase> Element::GetViewModel()
	{
		return m_viewModel;
	}

	// Visual tree
	shared_ptr<Element> Element::GetParent()
	{
		return m_parent;
	}

	shared_ptr<Element> Element::GetFirstChild()
	{
		return m_firstChild;
	}

	shared_ptr<Element> Element::GetLastChild()
	{
		return m_lastChild;
	}

	shared_ptr<Element> Element::GetPrevSibling()
	{
		return m_prevsibling;
	}
	shared_ptr<Element> Element::GetNextSibling()
	{
		return m_nextsibling;
	}

	void Element::RemoveChildren()
	{
		m_firstChild = nullptr;
		m_lastChild = nullptr;
		m_childrenCount = 0;
	}

	void Element::AddChild(shared_ptr<Element> element)
	{
		if (m_firstChild == nullptr)
		{
			m_firstChild = element;
		}
		else
		{
			element->m_prevsibling = m_lastChild;
			m_lastChild->m_nextsibling = element;
		}

		element->m_parent = shared_from_this();
		m_lastChild = element;

		m_childrenCount++;
	}

	int Element::GetChildrenCount()
	{
		return m_childrenCount;
	}

	void Element::SetSingleChild(shared_ptr<Element> child)
	{
		// Could be optimized to improve performance
		RemoveChildren();
		AddChild(child);
	}

	shared_ptr<Element> Element::GetSingleChild()
	{
		if (m_childrenCount == 1)
		{
			return m_firstChild;
		}

		if (m_childrenCount == 0)
		{
			return nullptr;
		}

		throw std::runtime_error("There is more than one child in this element");
	}

	// Cache Management
	void Element::ClearCache(int cacheLevel)
	{
		ClearElementCache(cacheLevel);

		// Recurse to children
		if (m_firstChild)
		{
			for (auto e = m_firstChild; e != nullptr; e = e->m_nextsibling)
			{
				e->ClearCache(cacheLevel);
			}
		}
	}

	void Element::ClearElementCache(int cacheLevel)
	{
		// This is intended to be overridden as needed for OS-specific needs.
	}

	// Arrangement
	void Element::ResetArrangement()
	{
		if (m_parent)
		{
			// Copy the element manager from the parent
			m_elementManager = m_parent->m_elementManager;
		}

		m_isVisible = true;

		m_left = 0;
		m_top = 0;
		m_right = 0;
		m_bottom = 0;
		m_centerX = 0;
		m_centerY = 0;
		m_width = 0;
		m_height = 0;

		m_isLeftSet = false;
		m_isTopSet = false;
		m_isRightSet = false;
		m_isBottomSet = false;
		m_isCenterXSet = false;
		m_isCenterYSet = false;
		m_isWidthSet = false;
		m_isHeightSet = false;
	}

	void Element::SetSetViewModelCallback(function<void(shared_ptr<Element>)> setViewModelCallback)
	{
		m_setViewModelCallback = setViewModelCallback;
	}

	void Element::PrepareViewModel()
	{
		if (m_setViewModelCallback)
		{
			m_setViewModelCallback(shared_from_this());
		}
		else
		{
			// By default the ViewModel is copied from the parent
			if (m_parent)
			{
				m_viewModel = m_parent->m_viewModel;
			}
		}
	}

	void Element::SetArrangeCallback(function<void(shared_ptr<Element>)> arrangeCallback)
	{
		m_arrangeCallback = arrangeCallback;
	}

	void Element::Arrange()
	{
		if (m_arrangeCallback)
		{
			m_arrangeCallback(shared_from_this());
		}
		else
		{
			// By default each element stretches
			// to fill its parent
			SetLeft(m_parent->GetLeft());
			SetTop(m_parent->GetTop());
			SetRight(m_parent->GetRight());
			SetBottom(m_parent->GetBottom());
		}
	}

	void Element::ArrangeAndDraw(bool draw)
	{
		ResetArrangement();
		PrepareViewModel();
		Arrange();
		if (draw && m_isVisible)
		{
			Draw();
			if (m_firstChild)
			{
				for (auto e = m_firstChild; e != nullptr; e = e->m_nextsibling)
				{
					e->ArrangeAndDraw(draw);
				}
			}
		}
	}

	void Element::SetIsVisible(bool isVisible)
	{
		m_isVisible = isVisible;
	}

	bool Element::GetIsVisible()
	{
		return m_isVisible;
	}

	void Element::SetLeft(double left)
	{
		m_isLeftSet = true;
		m_left = left;
	}

	void Element::SetTop(double top)
	{
		m_isTopSet = true;
		m_top = top;
	}

	void Element::SetRight(double right)
	{
		m_isRightSet = true;
		m_right = right;
	}

	void Element::SetBottom(double bottom)
	{
		m_isBottomSet = true;
		m_bottom = bottom;
	}

	void Element::SetCenterX(double centerX)
	{
		m_isCenterXSet = true;
		m_centerX = centerX;
	}

	void Element::SetCenterY(double centerY)
	{
		m_isCenterYSet = true;
		m_centerY = centerY;
	}

	void Element::SetWidth(double width)
	{
		m_isWidthSet = true;
		m_width = width;
	}

	void Element::SetHeight(double height)
	{
		m_isHeightSet = true;
		m_height = height;
	}

	double Element::GetLeft()
	{
		if (!m_isLeftSet)
		{
			if (m_isWidthSet)
			{
				if (m_isRightSet)
				{
					m_left = m_right - m_width;
				}
				else if (m_isCenterXSet)
				{
					m_left = m_centerX - (m_width / 2);
				}
			}
			m_isLeftSet = true;
		}
		return m_left;
	}

	double Element::GetTop()
	{
		if (!m_isTopSet)
		{
			if (m_isHeightSet)
			{
				if (m_isBottomSet)
				{
					m_top = m_bottom - m_height;
				}
				else if (m_isCenterYSet)
				{
					m_top = m_centerY - (m_height / 2);
				}
			}
			m_isTopSet = true;
		}
		return m_top;
	}

	double Element::GetRight()
	{
		if (!m_isRightSet)
		{
			if (m_isWidthSet)
			{
				if (m_isLeftSet)
				{
					m_right = m_left + m_width;
				}
				else if (m_isCenterXSet)
				{
					m_right = m_centerX + (m_width / 2);
				}
			}
			m_isRightSet = true;
		}
		return m_right;
	}

	double Element::GetBottom()
	{
		if (!m_isBottomSet)
		{
			if (m_isHeightSet)
			{
				if (m_isTopSet)
				{
					m_bottom = m_top + m_height;
				}
				else if (m_isCenterYSet)
				{
					m_bottom = m_centerY + (m_height / 2);
				}
			}
			m_isBottomSet = true;
		}
		return m_bottom;
	}

	double Element::GetCenterX()
	{
		if (!m_isCenterXSet)
		{
			if (m_isLeftSet && m_isRightSet)
			{
				m_centerX = m_left + (m_right - m_left) / 2;
			}
			else if (m_isLeftSet && m_isWidthSet)
			{
				m_centerX = m_left + (m_width / 2);
			}
			else if (m_isRightSet && m_isWidthSet)
			{
				m_centerX = m_right - (m_width / 2);
			}
			m_isCenterXSet = true;
		}
		return m_centerX;
	}

	double Element::GetCenterY()
	{
		if (!m_isCenterYSet)
		{
			if (m_isTopSet && m_isBottomSet)
			{
				m_centerY = m_top + (m_bottom - m_top) / 2;
			}
			else if (m_isTopSet && m_isHeightSet)
			{
				m_centerY = m_top + (m_height / 2);
			}
			else if (m_isBottomSet && m_isHeightSet)
			{
				m_centerY = m_bottom - (m_height / 2);
			}
			m_isCenterYSet = true;
		}
		return m_centerY;
	}

	double Element::GetWidth()
	{
		if (!m_isWidthSet)
		{
			if (m_isLeftSet && m_isRightSet)
			{
				m_width = m_right - m_left;
			}
			m_isWidthSet = true;
		}
		return m_width;
	}

	double Element::GetHeight()
	{
		if (!m_isHeightSet)
		{
			if (m_isTopSet && m_isBottomSet)
			{
				m_height = m_bottom - m_top;
			}
			m_isHeightSet = true;
		}
		return m_height;
	}

	// Drawing
	void Element::Draw()
	{
		if (m_drawCallback)
		{
			m_drawCallback(shared_from_this());
		}
		else
		{
			// By default no drawing takes place
		}
	}

	void Element::SetDrawCallback(function<void(shared_ptr<Element>)> drawCallback)
	{
		m_drawCallback = drawCallback;
	}

	// Hit testing
	shared_ptr<Element> Element::GetElementAtPoint(Location point)
	{
		if (m_firstChild)
		{
			for (auto e = m_lastChild; e != nullptr; e = e->m_prevsibling)
			{
				auto elementAtPoint = e->GetElementAtPoint(point);
				if (elementAtPoint)
				{
					return elementAtPoint;
				}
			}
		}

		if (point.x >= GetLeft() && point.x <= GetRight() &&
			point.y >= GetTop() && point.y <= GetBottom())
		{
			return shared_from_this();
		}
		return nullptr;
	}
}
<commit_msg>RemoveChildren now cleans all pointers between elements so that the elements will be deleted<commit_after>#include "Precompiled.h"
#include "Element.h"
#include "ElementManager.h"

namespace libgui
{
	// Element Manager
	void Element::SetElementManager(shared_ptr<ElementManager> elementManager)
	{
		m_elementManager = elementManager;
	}

	shared_ptr<ElementManager> Element::GetElementManager()
	{
		return m_elementManager;
	}

	// View Model
	void Element::SetViewModel(shared_ptr<ViewModelBase> viewModel)
	{
		m_viewModel = viewModel;
	}

	shared_ptr<ViewModelBase> Element::GetViewModel()
	{
		return m_viewModel;
	}

	// Visual tree
	shared_ptr<Element> Element::GetParent()
	{
		return m_parent;
	}

	shared_ptr<Element> Element::GetFirstChild()
	{
		return m_firstChild;
	}

	shared_ptr<Element> Element::GetLastChild()
	{
		return m_lastChild;
	}

	shared_ptr<Element> Element::GetPrevSibling()
	{
		return m_prevsibling;
	}
	shared_ptr<Element> Element::GetNextSibling()
	{
		return m_nextsibling;
	}

	void Element::RemoveChildren()
	{
		// Recurse into children to thoroughly clean the element tree
		auto e = m_firstChild;
		while (e != nullptr)
		{
			e->RemoveChildren();

			// Clean up pointers so that the class will be deleted
			e->m_parent = nullptr;
			e->m_prevsibling = nullptr;
			auto next_e = e->m_nextsibling;
			e->m_nextsibling = nullptr;
			e = next_e;
		}

		m_firstChild = nullptr;
		m_lastChild = nullptr;
		m_childrenCount = 0;
	}

	void Element::AddChild(shared_ptr<Element> element)
	{
		if (m_firstChild == nullptr)
		{
			m_firstChild = element;
		}
		else
		{
			element->m_prevsibling = m_lastChild;
			m_lastChild->m_nextsibling = element;
		}

		element->m_parent = shared_from_this();
		m_lastChild = element;

		m_childrenCount++;
	}

	int Element::GetChildrenCount()
	{
		return m_childrenCount;
	}

	void Element::SetSingleChild(shared_ptr<Element> child)
	{
		// Could be optimized to improve performance
		RemoveChildren();
		AddChild(child);
	}

	shared_ptr<Element> Element::GetSingleChild()
	{
		if (m_childrenCount == 1)
		{
			return m_firstChild;
		}

		if (m_childrenCount == 0)
		{
			return nullptr;
		}

		throw std::runtime_error("There is more than one child in this element");
	}

	// Cache Management
	void Element::ClearCache(int cacheLevel)
	{
		ClearElementCache(cacheLevel);

		// Recurse to children
		if (m_firstChild)
		{
			for (auto e = m_firstChild; e != nullptr; e = e->m_nextsibling)
			{
				e->ClearCache(cacheLevel);
			}
		}
	}

	void Element::ClearElementCache(int cacheLevel)
	{
		// This is intended to be overridden as needed for OS-specific needs.
	}

	// Arrangement
	void Element::ResetArrangement()
	{
		if (m_parent)
		{
			// Copy the element manager from the parent
			m_elementManager = m_parent->m_elementManager;
		}

		m_isVisible = true;

		m_left = 0;
		m_top = 0;
		m_right = 0;
		m_bottom = 0;
		m_centerX = 0;
		m_centerY = 0;
		m_width = 0;
		m_height = 0;

		m_isLeftSet = false;
		m_isTopSet = false;
		m_isRightSet = false;
		m_isBottomSet = false;
		m_isCenterXSet = false;
		m_isCenterYSet = false;
		m_isWidthSet = false;
		m_isHeightSet = false;
	}

	void Element::SetSetViewModelCallback(function<void(shared_ptr<Element>)> setViewModelCallback)
	{
		m_setViewModelCallback = setViewModelCallback;
	}

	void Element::PrepareViewModel()
	{
		if (m_setViewModelCallback)
		{
			m_setViewModelCallback(shared_from_this());
		}
		else
		{
			// By default the ViewModel is copied from the parent
			if (m_parent)
			{
				m_viewModel = m_parent->m_viewModel;
			}
		}
	}

	void Element::SetArrangeCallback(function<void(shared_ptr<Element>)> arrangeCallback)
	{
		m_arrangeCallback = arrangeCallback;
	}

	void Element::Arrange()
	{
		if (m_arrangeCallback)
		{
			m_arrangeCallback(shared_from_this());
		}
		else
		{
			// By default each element stretches
			// to fill its parent
			SetLeft(m_parent->GetLeft());
			SetTop(m_parent->GetTop());
			SetRight(m_parent->GetRight());
			SetBottom(m_parent->GetBottom());
		}
	}

	void Element::ArrangeAndDraw(bool draw)
	{
		ResetArrangement();
		PrepareViewModel();
		Arrange();
		if (draw && m_isVisible)
		{
			Draw();
			if (m_firstChild)
			{
				for (auto e = m_firstChild; e != nullptr; e = e->m_nextsibling)
				{
					e->ArrangeAndDraw(draw);
				}
			}
		}
	}

	void Element::SetIsVisible(bool isVisible)
	{
		m_isVisible = isVisible;
	}

	bool Element::GetIsVisible()
	{
		return m_isVisible;
	}

	void Element::SetLeft(double left)
	{
		m_isLeftSet = true;
		m_left = left;
	}

	void Element::SetTop(double top)
	{
		m_isTopSet = true;
		m_top = top;
	}

	void Element::SetRight(double right)
	{
		m_isRightSet = true;
		m_right = right;
	}

	void Element::SetBottom(double bottom)
	{
		m_isBottomSet = true;
		m_bottom = bottom;
	}

	void Element::SetCenterX(double centerX)
	{
		m_isCenterXSet = true;
		m_centerX = centerX;
	}

	void Element::SetCenterY(double centerY)
	{
		m_isCenterYSet = true;
		m_centerY = centerY;
	}

	void Element::SetWidth(double width)
	{
		m_isWidthSet = true;
		m_width = width;
	}

	void Element::SetHeight(double height)
	{
		m_isHeightSet = true;
		m_height = height;
	}

	double Element::GetLeft()
	{
		if (!m_isLeftSet)
		{
			if (m_isWidthSet)
			{
				if (m_isRightSet)
				{
					m_left = m_right - m_width;
				}
				else if (m_isCenterXSet)
				{
					m_left = m_centerX - (m_width / 2);
				}
			}
			m_isLeftSet = true;
		}
		return m_left;
	}

	double Element::GetTop()
	{
		if (!m_isTopSet)
		{
			if (m_isHeightSet)
			{
				if (m_isBottomSet)
				{
					m_top = m_bottom - m_height;
				}
				else if (m_isCenterYSet)
				{
					m_top = m_centerY - (m_height / 2);
				}
			}
			m_isTopSet = true;
		}
		return m_top;
	}

	double Element::GetRight()
	{
		if (!m_isRightSet)
		{
			if (m_isWidthSet)
			{
				if (m_isLeftSet)
				{
					m_right = m_left + m_width;
				}
				else if (m_isCenterXSet)
				{
					m_right = m_centerX + (m_width / 2);
				}
			}
			m_isRightSet = true;
		}
		return m_right;
	}

	double Element::GetBottom()
	{
		if (!m_isBottomSet)
		{
			if (m_isHeightSet)
			{
				if (m_isTopSet)
				{
					m_bottom = m_top + m_height;
				}
				else if (m_isCenterYSet)
				{
					m_bottom = m_centerY + (m_height / 2);
				}
			}
			m_isBottomSet = true;
		}
		return m_bottom;
	}

	double Element::GetCenterX()
	{
		if (!m_isCenterXSet)
		{
			if (m_isLeftSet && m_isRightSet)
			{
				m_centerX = m_left + (m_right - m_left) / 2;
			}
			else if (m_isLeftSet && m_isWidthSet)
			{
				m_centerX = m_left + (m_width / 2);
			}
			else if (m_isRightSet && m_isWidthSet)
			{
				m_centerX = m_right - (m_width / 2);
			}
			m_isCenterXSet = true;
		}
		return m_centerX;
	}

	double Element::GetCenterY()
	{
		if (!m_isCenterYSet)
		{
			if (m_isTopSet && m_isBottomSet)
			{
				m_centerY = m_top + (m_bottom - m_top) / 2;
			}
			else if (m_isTopSet && m_isHeightSet)
			{
				m_centerY = m_top + (m_height / 2);
			}
			else if (m_isBottomSet && m_isHeightSet)
			{
				m_centerY = m_bottom - (m_height / 2);
			}
			m_isCenterYSet = true;
		}
		return m_centerY;
	}

	double Element::GetWidth()
	{
		if (!m_isWidthSet)
		{
			if (m_isLeftSet && m_isRightSet)
			{
				m_width = m_right - m_left;
			}
			m_isWidthSet = true;
		}
		return m_width;
	}

	double Element::GetHeight()
	{
		if (!m_isHeightSet)
		{
			if (m_isTopSet && m_isBottomSet)
			{
				m_height = m_bottom - m_top;
			}
			m_isHeightSet = true;
		}
		return m_height;
	}

	// Drawing
	void Element::Draw()
	{
		if (m_drawCallback)
		{
			m_drawCallback(shared_from_this());
		}
		else
		{
			// By default no drawing takes place
		}
	}

	void Element::SetDrawCallback(function<void(shared_ptr<Element>)> drawCallback)
	{
		m_drawCallback = drawCallback;
	}

	// Hit testing
	shared_ptr<Element> Element::GetElementAtPoint(Location point)
	{
		if (m_firstChild)
		{
			for (auto e = m_lastChild; e != nullptr; e = e->m_prevsibling)
			{
				auto elementAtPoint = e->GetElementAtPoint(point);
				if (elementAtPoint)
				{
					return elementAtPoint;
				}
			}
		}

		if (point.x >= GetLeft() && point.x <= GetRight() &&
			point.y >= GetTop() && point.y <= GetBottom())
		{
			return shared_from_this();
		}
		return nullptr;
	}
}
<|endoftext|>