<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SkBitmapProcShader.h"
#include "SkColorPriv.h"
#include "SkFlattenableBuffers.h"
#include "SkPixelRef.h"

bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
    switch (bm.config()) {
        case SkBitmap::kA8_Config:
        case SkBitmap::kRGB_565_Config:
        case SkBitmap::kIndex8_Config:
        case SkBitmap::kARGB_8888_Config:
    //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
                return true;
        default:
            break;
    }
    return false;
}

SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
                                       TileMode tmx, TileMode tmy) {
    fRawBitmap = src;
    fState.fTileModeX = (uint8_t)tmx;
    fState.fTileModeY = (uint8_t)tmy;
    fFlags = 0; // computed in setContext
}

SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer) {
    buffer.readBitmap(&fRawBitmap);
    fRawBitmap.setImmutable();
    fState.fTileModeX = buffer.readUInt();
    fState.fTileModeY = buffer.readUInt();
    fFlags = 0; // computed in setContext
}

SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
                                                   SkMatrix* texM,
                                                   TileMode xy[]) const {
    if (texture) {
        *texture = fRawBitmap;
    }
    if (texM) {
        texM->reset();
    }
    if (xy) {
        xy[0] = (TileMode)fState.fTileModeX;
        xy[1] = (TileMode)fState.fTileModeY;
    }
    return kDefault_BitmapType;
}

void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);

    buffer.writeBitmap(fRawBitmap);
    buffer.writeUInt(fState.fTileModeX);
    buffer.writeUInt(fState.fTileModeY);
}

static bool only_scale_and_translate(const SkMatrix& matrix) {
    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
    return (matrix.getType() & ~mask) == 0;
}

bool SkBitmapProcShader::isOpaque() const {
    return fRawBitmap.isOpaque();
}

bool SkBitmapProcShader::setContext(const SkBitmap& device,
                                    const SkPaint& paint,
                                    const SkMatrix& matrix) {
    // do this first, so we have a correct inverse matrix
    if (!this->INHERITED::setContext(device, paint, matrix)) {
        return false;
    }

    fState.fOrigBitmap = fRawBitmap;
    fState.fOrigBitmap.lockPixels();
    if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
        fState.fOrigBitmap.unlockPixels();
        return false;
    }

    if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
        fState.fOrigBitmap.unlockPixels();
        return false;
    }

    const SkBitmap& bitmap = *fState.fBitmap;
    bool bitmapIsOpaque = bitmap.isOpaque();

    // update fFlags
    uint32_t flags = 0;
    if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
        flags |= kOpaqueAlpha_Flag;
    }

    switch (bitmap.config()) {
        case SkBitmap::kRGB_565_Config:
            flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
            break;
        case SkBitmap::kIndex8_Config:
        case SkBitmap::kARGB_8888_Config:
            if (bitmapIsOpaque) {
                flags |= kHasSpan16_Flag;
            }
            break;
        case SkBitmap::kA8_Config:
            break;  // never set kHasSpan16_Flag
        default:
            break;
    }

    if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
        // gradients can auto-dither in their 16bit sampler, but we don't so
        // we clear the flag here.
        flags &= ~kHasSpan16_Flag;
    }

    // if we're only 1-pixel heigh, and we don't rotate, then we can claim this
    if (1 == bitmap.height() &&
            only_scale_and_translate(this->getTotalInverse())) {
        flags |= kConstInY32_Flag;
        if (flags & kHasSpan16_Flag) {
            flags |= kConstInY16_Flag;
        }
    }

    fFlags = flags;
    return true;
}

void SkBitmapProcShader::endContext() {
    fState.fOrigBitmap.unlockPixels();
    this->INHERITED::endContext();
}

#define BUF_MAX     128

#define TEST_BUFFER_OVERRITEx

#ifdef TEST_BUFFER_OVERRITE
    #define TEST_BUFFER_EXTRA   32
    #define TEST_PATTERN    0x88888888
#else
    #define TEST_BUFFER_EXTRA   0
#endif

void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
    const SkBitmapProcState& state = fState;
    if (state.getShaderProc32()) {
        state.getShaderProc32()(state, x, y, dstC, count);
        return;
    }

    uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
    int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);

    SkASSERT(state.fBitmap->getPixels());
    SkASSERT(state.fBitmap->pixelRef() == NULL ||
             state.fBitmap->pixelRef()->isLocked());

    for (;;) {
        int n = count;
        if (n > max) {
            n = max;
        }
        SkASSERT(n > 0 && n < BUF_MAX*2);
#ifdef TEST_BUFFER_OVERRITE
        for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
            buffer[BUF_MAX + i] = TEST_PATTERN;
        }
#endif
        mproc(state, buffer, n, x, y);
#ifdef TEST_BUFFER_OVERRITE
        for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
            SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
        }
#endif
        sproc(state, buffer, n, dstC);

        if ((count -= n) == 0) {
            break;
        }
        SkASSERT(count > 0);
        x += n;
        dstC += n;
    }
}

SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
    if (fState.getShaderProc32()) {
        *ctx = &fState;
        return (ShadeProc)fState.getShaderProc32();
    }
    return NULL;
}

void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
    const SkBitmapProcState& state = fState;
    if (state.getShaderProc16()) {
        state.getShaderProc16()(state, x, y, dstC, count);
        return;
    }

    uint32_t buffer[BUF_MAX];
    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
    int max = fState.maxCountForBufferSize(sizeof(buffer));

    SkASSERT(state.fBitmap->getPixels());
    SkASSERT(state.fBitmap->pixelRef() == NULL ||
             state.fBitmap->pixelRef()->isLocked());

    for (;;) {
        int n = count;
        if (n > max) {
            n = max;
        }
        mproc(state, buffer, n, x, y);
        sproc(state, buffer, n, dstC);

        if ((count -= n) == 0) {
            break;
        }
        x += n;
        dstC += n;
    }
}

///////////////////////////////////////////////////////////////////////////////

#include "SkUnPreMultiply.h"
#include "SkColorShader.h"
#include "SkEmptyShader.h"

// returns true and set color if the bitmap can be drawn as a single color
// (for efficiency)
static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
    if (1 != bm.width() || 1 != bm.height()) {
        return false;
    }

    SkAutoLockPixels alp(bm);
    if (!bm.readyToDraw()) {
        return false;
    }

    switch (bm.config()) {
        case SkBitmap::kARGB_8888_Config:
            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
            return true;
        case SkBitmap::kRGB_565_Config:
            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
            return true;
        case SkBitmap::kIndex8_Config:
            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
            return true;
        default: // just skip the other configs for now
            break;
    }
    return false;
}

#include "SkTemplatesPriv.h"

static bool bitmapIsTooBig(const SkBitmap& bm) {
    // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
    // communicates between its matrix-proc and its sampler-proc. Until we can
    // widen that, we have to reject bitmaps that are larger.
    //
    const int maxSize = 65535;

    return bm.width() > maxSize || bm.height() > maxSize;
}

SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
                                       TileMode tmx, TileMode tmy,
                                       void* storage, size_t storageSize) {
    SkShader* shader;
    SkColor color;
    if (src.isNull() || bitmapIsTooBig(src)) {
        SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
    }
    else if (canUseColorShader(src, &color)) {
        SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
                              (color));
    } else {
        SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
                              storageSize, (src, tmx, tmy));
    }
    return shader;
}

///////////////////////////////////////////////////////////////////////////////

static const char* gTileModeName[] = {
    "clamp", "repeat", "mirror"
};

bool SkBitmapProcShader::toDumpString(SkString* str) const {
    str->printf("BitmapShader: [%d %d %d",
                fRawBitmap.width(), fRawBitmap.height(),
                fRawBitmap.bytesPerPixel());

    // add the pixelref
    SkPixelRef* pr = fRawBitmap.pixelRef();
    if (pr) {
        const char* uri = pr->getURI();
        if (uri) {
            str->appendf(" \"%s\"", uri);
        }
    }

    // add the (optional) matrix
    {
        if (this->hasLocalMatrix()) {
            SkString info;
            this->getLocalMatrix().toDumpString(&info);
            str->appendf(" %s", info.c_str());
        }
    }

    str->appendf(" [%s %s]]",
                 gTileModeName[fState.fTileModeX],
                 gTileModeName[fState.fTileModeY]);
    return true;
}
///////////////////////////////////////////////////////////////////////////////

#if SK_SUPPORT_GPU

#include "GrTextureAccess.h"
#include "effects/GrSingleTextureEffect.h"
#include "SkGr.h"

GrEffect* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
    SkMatrix matrix;
    matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());

    if (this->hasLocalMatrix()) {
        SkMatrix inverse;
        if (!this->getLocalMatrix().invert(&inverse)) {
            return false;
        }
        matrix.preConcat(inverse);
    }
    SkShader::TileMode tm[] = {
        (TileMode)fState.fTileModeX,
        (TileMode)fState.fTileModeY,
    };

    // Must set wrap and filter on the sampler before requesting a texture.
    GrTextureParams params(tm, paint.isFilterBitmap());
    GrTexture* texture = GrLockCachedBitmapTexture(context, fRawBitmap, &params);

    if (NULL == texture) {
        SkDebugf("Couldn't convert bitmap to texture.\n");
        return NULL;
    }

    GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix, params));
    GrUnlockCachedBitmapTexture(texture);
    return effect;
}
#endif
<commit_msg>false --> NULL for failure return<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SkBitmapProcShader.h"
#include "SkColorPriv.h"
#include "SkFlattenableBuffers.h"
#include "SkPixelRef.h"

bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
    switch (bm.config()) {
        case SkBitmap::kA8_Config:
        case SkBitmap::kRGB_565_Config:
        case SkBitmap::kIndex8_Config:
        case SkBitmap::kARGB_8888_Config:
    //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
                return true;
        default:
            break;
    }
    return false;
}

SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
                                       TileMode tmx, TileMode tmy) {
    fRawBitmap = src;
    fState.fTileModeX = (uint8_t)tmx;
    fState.fTileModeY = (uint8_t)tmy;
    fFlags = 0; // computed in setContext
}

SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer) {
    buffer.readBitmap(&fRawBitmap);
    fRawBitmap.setImmutable();
    fState.fTileModeX = buffer.readUInt();
    fState.fTileModeY = buffer.readUInt();
    fFlags = 0; // computed in setContext
}

SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
                                                   SkMatrix* texM,
                                                   TileMode xy[]) const {
    if (texture) {
        *texture = fRawBitmap;
    }
    if (texM) {
        texM->reset();
    }
    if (xy) {
        xy[0] = (TileMode)fState.fTileModeX;
        xy[1] = (TileMode)fState.fTileModeY;
    }
    return kDefault_BitmapType;
}

void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);

    buffer.writeBitmap(fRawBitmap);
    buffer.writeUInt(fState.fTileModeX);
    buffer.writeUInt(fState.fTileModeY);
}

static bool only_scale_and_translate(const SkMatrix& matrix) {
    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
    return (matrix.getType() & ~mask) == 0;
}

bool SkBitmapProcShader::isOpaque() const {
    return fRawBitmap.isOpaque();
}

bool SkBitmapProcShader::setContext(const SkBitmap& device,
                                    const SkPaint& paint,
                                    const SkMatrix& matrix) {
    // do this first, so we have a correct inverse matrix
    if (!this->INHERITED::setContext(device, paint, matrix)) {
        return false;
    }

    fState.fOrigBitmap = fRawBitmap;
    fState.fOrigBitmap.lockPixels();
    if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
        fState.fOrigBitmap.unlockPixels();
        return false;
    }

    if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
        fState.fOrigBitmap.unlockPixels();
        return false;
    }

    const SkBitmap& bitmap = *fState.fBitmap;
    bool bitmapIsOpaque = bitmap.isOpaque();

    // update fFlags
    uint32_t flags = 0;
    if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
        flags |= kOpaqueAlpha_Flag;
    }

    switch (bitmap.config()) {
        case SkBitmap::kRGB_565_Config:
            flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
            break;
        case SkBitmap::kIndex8_Config:
        case SkBitmap::kARGB_8888_Config:
            if (bitmapIsOpaque) {
                flags |= kHasSpan16_Flag;
            }
            break;
        case SkBitmap::kA8_Config:
            break;  // never set kHasSpan16_Flag
        default:
            break;
    }

    if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
        // gradients can auto-dither in their 16bit sampler, but we don't so
        // we clear the flag here.
        flags &= ~kHasSpan16_Flag;
    }

    // if we're only 1-pixel heigh, and we don't rotate, then we can claim this
    if (1 == bitmap.height() &&
            only_scale_and_translate(this->getTotalInverse())) {
        flags |= kConstInY32_Flag;
        if (flags & kHasSpan16_Flag) {
            flags |= kConstInY16_Flag;
        }
    }

    fFlags = flags;
    return true;
}

void SkBitmapProcShader::endContext() {
    fState.fOrigBitmap.unlockPixels();
    this->INHERITED::endContext();
}

#define BUF_MAX     128

#define TEST_BUFFER_OVERRITEx

#ifdef TEST_BUFFER_OVERRITE
    #define TEST_BUFFER_EXTRA   32
    #define TEST_PATTERN    0x88888888
#else
    #define TEST_BUFFER_EXTRA   0
#endif

void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
    const SkBitmapProcState& state = fState;
    if (state.getShaderProc32()) {
        state.getShaderProc32()(state, x, y, dstC, count);
        return;
    }

    uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
    int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);

    SkASSERT(state.fBitmap->getPixels());
    SkASSERT(state.fBitmap->pixelRef() == NULL ||
             state.fBitmap->pixelRef()->isLocked());

    for (;;) {
        int n = count;
        if (n > max) {
            n = max;
        }
        SkASSERT(n > 0 && n < BUF_MAX*2);
#ifdef TEST_BUFFER_OVERRITE
        for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
            buffer[BUF_MAX + i] = TEST_PATTERN;
        }
#endif
        mproc(state, buffer, n, x, y);
#ifdef TEST_BUFFER_OVERRITE
        for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
            SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
        }
#endif
        sproc(state, buffer, n, dstC);

        if ((count -= n) == 0) {
            break;
        }
        SkASSERT(count > 0);
        x += n;
        dstC += n;
    }
}

SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
    if (fState.getShaderProc32()) {
        *ctx = &fState;
        return (ShadeProc)fState.getShaderProc32();
    }
    return NULL;
}

void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
    const SkBitmapProcState& state = fState;
    if (state.getShaderProc16()) {
        state.getShaderProc16()(state, x, y, dstC, count);
        return;
    }

    uint32_t buffer[BUF_MAX];
    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
    int max = fState.maxCountForBufferSize(sizeof(buffer));

    SkASSERT(state.fBitmap->getPixels());
    SkASSERT(state.fBitmap->pixelRef() == NULL ||
             state.fBitmap->pixelRef()->isLocked());

    for (;;) {
        int n = count;
        if (n > max) {
            n = max;
        }
        mproc(state, buffer, n, x, y);
        sproc(state, buffer, n, dstC);

        if ((count -= n) == 0) {
            break;
        }
        x += n;
        dstC += n;
    }
}

///////////////////////////////////////////////////////////////////////////////

#include "SkUnPreMultiply.h"
#include "SkColorShader.h"
#include "SkEmptyShader.h"

// returns true and set color if the bitmap can be drawn as a single color
// (for efficiency)
static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
    if (1 != bm.width() || 1 != bm.height()) {
        return false;
    }

    SkAutoLockPixels alp(bm);
    if (!bm.readyToDraw()) {
        return false;
    }

    switch (bm.config()) {
        case SkBitmap::kARGB_8888_Config:
            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
            return true;
        case SkBitmap::kRGB_565_Config:
            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
            return true;
        case SkBitmap::kIndex8_Config:
            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
            return true;
        default: // just skip the other configs for now
            break;
    }
    return false;
}

#include "SkTemplatesPriv.h"

static bool bitmapIsTooBig(const SkBitmap& bm) {
    // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
    // communicates between its matrix-proc and its sampler-proc. Until we can
    // widen that, we have to reject bitmaps that are larger.
    //
    const int maxSize = 65535;

    return bm.width() > maxSize || bm.height() > maxSize;
}

SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
                                       TileMode tmx, TileMode tmy,
                                       void* storage, size_t storageSize) {
    SkShader* shader;
    SkColor color;
    if (src.isNull() || bitmapIsTooBig(src)) {
        SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
    }
    else if (canUseColorShader(src, &color)) {
        SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
                              (color));
    } else {
        SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
                              storageSize, (src, tmx, tmy));
    }
    return shader;
}

///////////////////////////////////////////////////////////////////////////////

static const char* gTileModeName[] = {
    "clamp", "repeat", "mirror"
};

bool SkBitmapProcShader::toDumpString(SkString* str) const {
    str->printf("BitmapShader: [%d %d %d",
                fRawBitmap.width(), fRawBitmap.height(),
                fRawBitmap.bytesPerPixel());

    // add the pixelref
    SkPixelRef* pr = fRawBitmap.pixelRef();
    if (pr) {
        const char* uri = pr->getURI();
        if (uri) {
            str->appendf(" \"%s\"", uri);
        }
    }

    // add the (optional) matrix
    {
        if (this->hasLocalMatrix()) {
            SkString info;
            this->getLocalMatrix().toDumpString(&info);
            str->appendf(" %s", info.c_str());
        }
    }

    str->appendf(" [%s %s]]",
                 gTileModeName[fState.fTileModeX],
                 gTileModeName[fState.fTileModeY]);
    return true;
}
///////////////////////////////////////////////////////////////////////////////

#if SK_SUPPORT_GPU

#include "GrTextureAccess.h"
#include "effects/GrSingleTextureEffect.h"
#include "SkGr.h"

GrEffect* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
    SkMatrix matrix;
    matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());

    if (this->hasLocalMatrix()) {
        SkMatrix inverse;
        if (!this->getLocalMatrix().invert(&inverse)) {
            return NULL;
        }
        matrix.preConcat(inverse);
    }
    SkShader::TileMode tm[] = {
        (TileMode)fState.fTileModeX,
        (TileMode)fState.fTileModeY,
    };

    // Must set wrap and filter on the sampler before requesting a texture.
    GrTextureParams params(tm, paint.isFilterBitmap());
    GrTexture* texture = GrLockCachedBitmapTexture(context, fRawBitmap, &params);

    if (NULL == texture) {
        SkDebugf("Couldn't convert bitmap to texture.\n");
        return NULL;
    }

    GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix, params));
    GrUnlockCachedBitmapTexture(texture);
    return effect;
}
#endif
<|endoftext|>


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

#include <grpc/support/port_platform.h>

#include "src/core/lib/gprpp/host_port.h"

#include <string.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>

#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/string_view.h"

namespace grpc_core {
int JoinHostPort(grpc_core::UniquePtr<char>* out, const char* host, int port) {
  char* tmp;
  int ret;
  if (host[0] != '[' && strchr(host, ':') != nullptr) {
    /* IPv6 literals must be enclosed in brackets. */
    ret = gpr_asprintf(&tmp, "[%s]:%d", host, port);
  } else {
    /* Ordinary non-bracketed host:port. */
    ret = gpr_asprintf(&tmp, "%s:%d", host, port);
  }
  out->reset(tmp);
  return ret;
}

namespace {
bool DoSplitHostPort(StringView name, StringView* host, StringView* port,
                     bool* has_port) {
  *has_port = false;
  if (name[0] == '[') {
    /* Parse a bracketed host, typically an IPv6 literal. */
    const size_t rbracket = name.find(']', 1);
    if (rbracket == grpc_core::StringView::npos) {
      /* Unmatched [ */
      return false;
    }
    if (rbracket == name.size() - 1) {
      /* ]<end> */
      *port = StringView();
    } else if (name[rbracket + 1] == ':') {
      /* ]:<port?> */
      *port = name.substr(rbracket + 2, name.size() - rbracket - 2);
      *has_port = true;
    } else {
      /* ]<invalid> */
      return false;
    }
    *host = name.substr(1, rbracket - 1);
    if (host->find(':') == grpc_core::StringView::npos) {
      /* Require all bracketed hosts to contain a colon, because a hostname or
         IPv4 address should never use brackets. */
      *host = StringView();
      return false;
    }
  } else {
    size_t colon = name.find(':');
    if (colon != grpc_core::StringView::npos &&
        name.find(':', colon + 1) == grpc_core::StringView::npos) {
      /* Exactly 1 colon.  Split into host:port. */
      *host = name.substr(0, colon);
      *port = name.substr(colon + 1, name.size() - colon - 1);
      *has_port = true;
    } else {
      /* 0 or 2+ colons.  Bare hostname or IPv6 litearal. */
      *host = name;
      *port = StringView();
    }
  }
  return true;
}
}  // namespace

bool SplitHostPort(StringView name, StringView* host, StringView* port) {
  bool unused;
  return DoSplitHostPort(name, host, port, &unused);
}

bool SplitHostPort(StringView name, grpc_core::UniquePtr<char>* host,
                   grpc_core::UniquePtr<char>* port) {
  GPR_DEBUG_ASSERT(host != nullptr && *host == nullptr);
  GPR_DEBUG_ASSERT(port != nullptr && *port == nullptr);
  StringView host_view;
  StringView port_view;
  bool has_port;
  const bool ret = DoSplitHostPort(name, &host_view, &port_view, &has_port);
  if (ret) {
    // We always set the host, but port is set only when DoSplitHostPort find a
    // port in the string, to remain backward compatible with the old
    // gpr_split_host_port API.
    *host = StringViewToCString(host_view);
    if (has_port) {
      *port = StringViewToCString(port_view);
    }
  }
  return ret;
}
}  // namespace grpc_core
<commit_msg>Fix illegal access<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <grpc/support/port_platform.h>

#include "src/core/lib/gprpp/host_port.h"

#include <string.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>

#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/string_view.h"

namespace grpc_core {
int JoinHostPort(grpc_core::UniquePtr<char>* out, const char* host, int port) {
  char* tmp;
  int ret;
  if (host[0] != '[' && strchr(host, ':') != nullptr) {
    /* IPv6 literals must be enclosed in brackets. */
    ret = gpr_asprintf(&tmp, "[%s]:%d", host, port);
  } else {
    /* Ordinary non-bracketed host:port. */
    ret = gpr_asprintf(&tmp, "%s:%d", host, port);
  }
  out->reset(tmp);
  return ret;
}

namespace {
bool DoSplitHostPort(StringView name, StringView* host, StringView* port,
                     bool* has_port) {
  *has_port = false;
  if (!name.empty() && name[0] == '[') {
    /* Parse a bracketed host, typically an IPv6 literal. */
    const size_t rbracket = name.find(']', 1);
    if (rbracket == grpc_core::StringView::npos) {
      /* Unmatched [ */
      return false;
    }
    if (rbracket == name.size() - 1) {
      /* ]<end> */
      *port = StringView();
    } else if (name[rbracket + 1] == ':') {
      /* ]:<port?> */
      *port = name.substr(rbracket + 2, name.size() - rbracket - 2);
      *has_port = true;
    } else {
      /* ]<invalid> */
      return false;
    }
    *host = name.substr(1, rbracket - 1);
    if (host->find(':') == grpc_core::StringView::npos) {
      /* Require all bracketed hosts to contain a colon, because a hostname or
         IPv4 address should never use brackets. */
      *host = StringView();
      return false;
    }
  } else {
    size_t colon = name.find(':');
    if (colon != grpc_core::StringView::npos &&
        name.find(':', colon + 1) == grpc_core::StringView::npos) {
      /* Exactly 1 colon.  Split into host:port. */
      *host = name.substr(0, colon);
      *port = name.substr(colon + 1, name.size() - colon - 1);
      *has_port = true;
    } else {
      /* 0 or 2+ colons.  Bare hostname or IPv6 litearal. */
      *host = name;
      *port = StringView();
    }
  }
  return true;
}
}  // namespace

bool SplitHostPort(StringView name, StringView* host, StringView* port) {
  bool unused;
  return DoSplitHostPort(name, host, port, &unused);
}

bool SplitHostPort(StringView name, grpc_core::UniquePtr<char>* host,
                   grpc_core::UniquePtr<char>* port) {
  GPR_DEBUG_ASSERT(host != nullptr && *host == nullptr);
  GPR_DEBUG_ASSERT(port != nullptr && *port == nullptr);
  StringView host_view;
  StringView port_view;
  bool has_port;
  const bool ret = DoSplitHostPort(name, &host_view, &port_view, &has_port);
  if (ret) {
    // We always set the host, but port is set only when DoSplitHostPort find a
    // port in the string, to remain backward compatible with the old
    // gpr_split_host_port API.
    *host = StringViewToCString(host_view);
    if (has_port) {
      *port = StringViewToCString(port_view);
    }
  }
  return ret;
}
}  // namespace grpc_core
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// QUESO - a library to support the Quantification of Uncertainty
// for Estimation, Simulation and Optimization
//
// Copyright (C) 2008,2009,2010,2011,2012,2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License 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. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

#include <string>
#include <iomanip>
#include <queso/OptimizerMonitor.h>

namespace QUESO
{

  OptimizerMonitor::OptimizerMonitor( unsigned int n_iters )
    : m_display_conv(false),
      m_print_xmin(false)
  {
    m_minimizer_hist.reserve(n_iters);
    m_objective_hist.reserve(n_iters);
    m_norm_hist.reserve(n_iters);
  }

  OptimizerMonitor::~OptimizerMonitor()
  {}

  void OptimizerMonitor::set_display_output( bool enable_output, bool print_xmin )
  {
    m_display_conv = enable_output;
    m_print_xmin = print_xmin;
  }

  void OptimizerMonitor::append( std::vector<double>& x_min, double objective, double norm )
  {
    m_minimizer_hist.push_back(x_min);
    m_objective_hist.push_back(objective);
    m_norm_hist.push_back(norm);

    // Print out to screen if the user set the option
    if( m_display_conv )
      {
        // If we are appending the first entry, print a nice header
        if( m_minimizer_hist.size() == 1 )
          {
            this->print_header(std::cout);
          }

        // We're assuming here the size of the array is the current iteration
        this->print_iteration(m_norm_hist.size(),std::cout);
      }

  }

  void OptimizerMonitor::print_header( std::ostream& output ) const
  {
    unsigned int width = 35;

    if( m_print_xmin) width += (m_minimizer_hist[0]).size()*12;

    output.width(5);
    output << "i";

    if( m_print_xmin)
      {
        for( unsigned int i = 0; i < m_minimizer_hist[0].size(); i++ )
          {
            output.width(8);
            output << "x" << i << std::string(5,' ');
          }
      }

    output.width(8);
    output << "f" << std::string(5,' ');

    output.width(11);
    output << "norm" << std::endl;
    output << std::string(width,'-') << std::endl;
  }

  void OptimizerMonitor::print_iteration( unsigned int iter, std::ostream& output ) const
  {
    output.width(5);
    output << iter;

    if( m_print_xmin)
      {
        for( unsigned int i = 0; i < m_minimizer_hist[iter-1].size(); i++ )
          {
            output.width(2);
            output << "  ";
            output.width(12);
            output << std::scientific << m_minimizer_hist[iter-1][i];
          }
      }

    output.width(2);
    output << "  ";
    output.width(12);
    output << std::scientific << m_objective_hist[iter-1];

    output.width(2);
    output << "  ";
    output.width(12);
    output << m_norm_hist[iter-1] << std::endl;
  }

} // end namespace QUESO
<commit_msg>Mucking with spacing for output.<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// QUESO - a library to support the Quantification of Uncertainty
// for Estimation, Simulation and Optimization
//
// Copyright (C) 2008,2009,2010,2011,2012,2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License 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. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

#include <string>
#include <iomanip>
#include <queso/OptimizerMonitor.h>

namespace QUESO
{

  OptimizerMonitor::OptimizerMonitor( unsigned int n_iters )
    : m_display_conv(false),
      m_print_xmin(false)
  {
    m_minimizer_hist.reserve(n_iters);
    m_objective_hist.reserve(n_iters);
    m_norm_hist.reserve(n_iters);
  }

  OptimizerMonitor::~OptimizerMonitor()
  {}

  void OptimizerMonitor::set_display_output( bool enable_output, bool print_xmin )
  {
    m_display_conv = enable_output;
    m_print_xmin = print_xmin;
  }

  void OptimizerMonitor::append( std::vector<double>& x_min, double objective, double norm )
  {
    m_minimizer_hist.push_back(x_min);
    m_objective_hist.push_back(objective);
    m_norm_hist.push_back(norm);

    // Print out to screen if the user set the option
    if( m_display_conv )
      {
        // If we are appending the first entry, print a nice header
        if( m_minimizer_hist.size() == 1 )
          {
            this->print_header(std::cout);
          }

        // We're assuming here the size of the array is the current iteration
        this->print_iteration(m_norm_hist.size(),std::cout);
      }

  }

  void OptimizerMonitor::print_header( std::ostream& output ) const
  {
    unsigned int width = 37;

    if( m_print_xmin) width += (m_minimizer_hist[0]).size()*15;

    output.width(5);
    output << "i";

    if( m_print_xmin)
      {
        for( unsigned int i = 0; i < m_minimizer_hist[0].size(); i++ )
          {
            output.width(9);
            output << "x" << i << std::string(5,' ');
          }
      }

    output.width(9);
    output << "f" << std::string(5,' ');

    output.width(12);
    output << "norm" << std::endl;
    output << std::string(width,'-') << std::endl;
  }

  void OptimizerMonitor::print_iteration( unsigned int iter, std::ostream& output ) const
  {
    output.width(5);
    output << iter;

    if( m_print_xmin)
      {
        for( unsigned int i = 0; i < m_minimizer_hist[iter-1].size(); i++ )
          {
            output.width(2);
            output << "  ";
            output.width(13);
            output << std::scientific << m_minimizer_hist[iter-1][i];
          }
      }

    output.width(2);
    output << "  ";
    output.width(13);
    output << std::scientific << m_objective_hist[iter-1];

    output.width(2);
    output << "  ";
    output.width(13);
    output << m_norm_hist[iter-1] << std::endl;
  }

} // end namespace QUESO
<|endoftext|>


<commit_before>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "dialog/file.h"
#include "dialog/list.h"
#include "dialog/image_properties.h"
#include "opengl/gl.h"

#include "image/header.h"

namespace MR {
  namespace Dialog {

    ImageProperties::ImageProperties (QWidget* parent, const Image::Header& header) :
      QDialog (parent), H (header), save_target (NULL)
    {
      model = new TreeModel (this);

      TreeItem* root = model->rootItem;

      root->appendChild (new TreeItem ("File", H.name(), root));
      root->appendChild (new TreeItem ("Format", H.format, root));

      if (H.comments.size()) {
        TreeItem* comments = new TreeItem ("Comments", std::string(), root);
        root->appendChild (comments);
        for (size_t n = 0; n < H.comments.size(); ++n)
          comments->appendChild (new TreeItem (std::string(), H.comments[n], comments));
      }

      std::string text;
      text = str (H.dim(0));
      for (size_t n = 1; n < H.ndim(); ++n)
        text += " x " + str (H.dim(n));
      root->appendChild (new TreeItem ("Dimensions", text, root));

      text = str (H.vox(0));
      for (size_t n = 1; n < H.ndim(); ++n)
        text += " x " + str (H.vox(n));
      root->appendChild (new TreeItem ("Voxel size", text, root));

      TreeItem* labels = new TreeItem ("Axes labels", std::string(), root);
      root->appendChild (labels);
      for (size_t n = 0; n < H.ndim(); ++n)
        labels->appendChild (new TreeItem (std::string(),
        ( H.axes.description(n).size() ? H.axes.description(n) : "undefined" ) +
        " (" + ( H.axes.units(n).size() ? H.axes.units(n) : "?" ) + ")", labels));

      root->appendChild (new TreeItem ("Data type", H.datatype().description(), root));

      text = str (H.stride(0));
      for (size_t n = 1; n < H.ndim(); ++n)
        text += ", " + str (H.stride(n));
      root->appendChild (new TreeItem ("Strides", text, root));

      root->appendChild (new TreeItem ("Data scaling",
            "offset: " + str (H.offset) + ", multiplier = " + str (H.scale), root));

      if (H.transform().rows() != 4 || H.transform().columns() != 4) {
        root->appendChild (new TreeItem ("Transform", "(invalid)", root));
      }
      else {
        TreeItem* transform = new TreeItem ("Transform", std::string(), root);
        root->appendChild (transform);
        for (size_t n = 0; n < 4; ++n)
          transform->appendChild (new TreeItem (std::string(),
                str (H.transform()(n,0)) + ", " +
                str (H.transform()(n,1)) + ", " +
                str (H.transform()(n,2)) + ", " +
                str (H.transform()(n,3)),
                transform));
      }

      if (H.DW_scheme.is_set()) {
        if (H.DW_scheme.rows() == 0 || H.DW_scheme.columns() != 4) {
          root->appendChild (new TreeItem ("Diffusion scheme", "(invalid)", root));
        }
        else {
          TreeItem* scheme = new TreeItem ("Diffusion scheme", std::string(), root);
          root->appendChild (scheme);
          for (size_t n = 0; n < H.DW_scheme.rows(); ++n)
            scheme->appendChild (new TreeItem (std::string(),
                  str (H.DW_scheme(n,0)) + ", " +
                  str (H.DW_scheme(n,1)) + ", " +
                  str (H.DW_scheme(n,2)) + ", " +
                  str (H.DW_scheme(n,3)),
                  scheme));
        }
      }

      view = new QTreeView;
      view->setModel (model);
      view->resizeColumnToContents (0);
      view->resizeColumnToContents (1);
      view->setMinimumSize (500, 200);
      view->setContextMenuPolicy(Qt::CustomContextMenu);
      connect (view, SIGNAL (customContextMenuRequested (const QPoint&)),
          this, SLOT (context_menu (const QPoint&)));

      QDialogButtonBox* buttonBox = new QDialogButtonBox (QDialogButtonBox::Ok);
      connect (buttonBox, SIGNAL(accepted()), this, SLOT(accept()));

      QVBoxLayout* layout = new QVBoxLayout (this);
      layout->addWidget (view);
      layout->addWidget (buttonBox);
      setLayout (layout);

      setWindowTitle (tr("OpenGL information"));
      setSizeGripEnabled (true);
      adjustSize();
    }

    void ImageProperties::context_menu (const QPoint& point)
    {
      QModelIndex k = view->indexAt (point);
      if (!k.isValid()) return;
      k = k.sibling (k.row(), 0);

      while (k.parent().isValid()) k = k.parent();
      std::string text = k.data().toString().toAscii().constData();

      if (text == "Transform") save_target = &H.transform();
      else if (text == "Diffusion scheme") save_target = &H.DW_scheme;
      else { save_target = NULL; return; }

      QAction* save_action = new QAction (tr("&Save as..."), this);
      connect (save_action, SIGNAL (triggered()), this, SLOT (write_to_file()));

      QMenu menu (this);
      menu.addAction (save_action);
      menu.exec (view->viewport()->mapToGlobal (point));
    }

    void ImageProperties::write_to_file ()
    {
      assert (save_target);
      File dialog (this, "Save as...", false, false);
      if (dialog.exec()) {
        std::vector<std::string> selection;
        dialog.get_selection (selection);
        if (selection.empty()) return;
        save_target->save (selection[0]);
      }
    }

  }
}

<commit_msg>fix wrong title for image property window<commit_after>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "dialog/file.h"
#include "dialog/list.h"
#include "dialog/image_properties.h"
#include "opengl/gl.h"

#include "image/header.h"

namespace MR {
  namespace Dialog {

    ImageProperties::ImageProperties (QWidget* parent, const Image::Header& header) :
      QDialog (parent), H (header), save_target (NULL)
    {
      model = new TreeModel (this);

      TreeItem* root = model->rootItem;

      root->appendChild (new TreeItem ("File", H.name(), root));
      root->appendChild (new TreeItem ("Format", H.format, root));

      if (H.comments.size()) {
        TreeItem* comments = new TreeItem ("Comments", std::string(), root);
        root->appendChild (comments);
        for (size_t n = 0; n < H.comments.size(); ++n)
          comments->appendChild (new TreeItem (std::string(), H.comments[n], comments));
      }

      std::string text;
      text = str (H.dim(0));
      for (size_t n = 1; n < H.ndim(); ++n)
        text += " x " + str (H.dim(n));
      root->appendChild (new TreeItem ("Dimensions", text, root));

      text = str (H.vox(0));
      for (size_t n = 1; n < H.ndim(); ++n)
        text += " x " + str (H.vox(n));
      root->appendChild (new TreeItem ("Voxel size", text, root));

      TreeItem* labels = new TreeItem ("Axes labels", std::string(), root);
      root->appendChild (labels);
      for (size_t n = 0; n < H.ndim(); ++n)
        labels->appendChild (new TreeItem (std::string(),
        ( H.axes.description(n).size() ? H.axes.description(n) : "undefined" ) +
        " (" + ( H.axes.units(n).size() ? H.axes.units(n) : "?" ) + ")", labels));

      root->appendChild (new TreeItem ("Data type", H.datatype().description(), root));

      text = str (H.stride(0));
      for (size_t n = 1; n < H.ndim(); ++n)
        text += ", " + str (H.stride(n));
      root->appendChild (new TreeItem ("Strides", text, root));

      root->appendChild (new TreeItem ("Data scaling",
            "offset: " + str (H.offset) + ", multiplier = " + str (H.scale), root));

      if (H.transform().rows() != 4 || H.transform().columns() != 4) {
        root->appendChild (new TreeItem ("Transform", "(invalid)", root));
      }
      else {
        TreeItem* transform = new TreeItem ("Transform", std::string(), root);
        root->appendChild (transform);
        for (size_t n = 0; n < 4; ++n)
          transform->appendChild (new TreeItem (std::string(),
                str (H.transform()(n,0)) + ", " +
                str (H.transform()(n,1)) + ", " +
                str (H.transform()(n,2)) + ", " +
                str (H.transform()(n,3)),
                transform));
      }

      if (H.DW_scheme.is_set()) {
        if (H.DW_scheme.rows() == 0 || H.DW_scheme.columns() != 4) {
          root->appendChild (new TreeItem ("Diffusion scheme", "(invalid)", root));
        }
        else {
          TreeItem* scheme = new TreeItem ("Diffusion scheme", std::string(), root);
          root->appendChild (scheme);
          for (size_t n = 0; n < H.DW_scheme.rows(); ++n)
            scheme->appendChild (new TreeItem (std::string(),
                  str (H.DW_scheme(n,0)) + ", " +
                  str (H.DW_scheme(n,1)) + ", " +
                  str (H.DW_scheme(n,2)) + ", " +
                  str (H.DW_scheme(n,3)),
                  scheme));
        }
      }

      view = new QTreeView;
      view->setModel (model);
      view->resizeColumnToContents (0);
      view->resizeColumnToContents (1);
      view->setMinimumSize (500, 200);
      view->setContextMenuPolicy(Qt::CustomContextMenu);
      connect (view, SIGNAL (customContextMenuRequested (const QPoint&)),
          this, SLOT (context_menu (const QPoint&)));

      QDialogButtonBox* buttonBox = new QDialogButtonBox (QDialogButtonBox::Ok);
      connect (buttonBox, SIGNAL(accepted()), this, SLOT(accept()));

      QVBoxLayout* layout = new QVBoxLayout (this);
      layout->addWidget (view);
      layout->addWidget (buttonBox);
      setLayout (layout);

      setWindowTitle (tr("Image Properties"));
      setSizeGripEnabled (true);
      adjustSize();
    }

    void ImageProperties::context_menu (const QPoint& point)
    {
      QModelIndex k = view->indexAt (point);
      if (!k.isValid()) return;
      k = k.sibling (k.row(), 0);

      while (k.parent().isValid()) k = k.parent();
      std::string text = k.data().toString().toAscii().constData();

      if (text == "Transform") save_target = &H.transform();
      else if (text == "Diffusion scheme") save_target = &H.DW_scheme;
      else { save_target = NULL; return; }

      QAction* save_action = new QAction (tr("&Save as..."), this);
      connect (save_action, SIGNAL (triggered()), this, SLOT (write_to_file()));

      QMenu menu (this);
      menu.addAction (save_action);
      menu.exec (view->viewport()->mapToGlobal (point));
    }

    void ImageProperties::write_to_file ()
    {
      assert (save_target);
      File dialog (this, "Save as...", false, false);
      if (dialog.exec()) {
        std::vector<std::string> selection;
        dialog.get_selection (selection);
        if (selection.empty()) return;
        save_target->save (selection[0]);
      }
    }

  }
}

<|endoftext|>


<commit_before>/***************************************************************************
*   Copyright © 2003-2005 Jason Kivlighn <jkivlighn@gmail.com>            *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
***************************************************************************/

#include "pagesetupdialog.h"

#include <QDir>

#include <QFileInfo>
#include <QPushButton>
#include <q3popupmenu.h>
#include <QLabel>
//Added by qt3to4:
#include <Q3ValueList>
#include <QVBoxLayout>
#include <q3tl.h>

#include <khtmlview.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kfiledialog.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kaction.h>
#include <kconfig.h>
#include <kstandardaction.h>
#include <ktoolbar.h>
#include <ktoolbarpopupaction.h>
#include <kmenu.h>
#include <KActionCollection>

#include <widgets/thumbbar.h>
#include <kglobal.h>
#include <kvbox.h>
#include "setupdisplay.h"

PageSetupDialog::PageSetupDialog( QWidget *parent, const Recipe &sample, const QString &configEntry )
	: KDialog( parent ), m_configEntry(configEntry)
{
	QWidget *w = new QWidget;
	QVBoxLayout * layout = new QVBoxLayout( this );
	w->setLayout( layout );
	setButtons( KDialog::None );
	setMainWidget( w );
	KToolBar *toolbar = new KToolBar( this );
	KActionCollection *actionCollection = new KActionCollection( this );
	setCaption( i18n("Page Setup") );

	toolbar->addAction( KStandardAction::open( this, SLOT(loadFile()), actionCollection ) );
	toolbar->addAction( KStandardAction::save( this, SLOT( saveLayout() ), actionCollection ) );
	toolbar->addAction( KStandardAction::saveAs( this, SLOT( saveAsLayout() ), actionCollection ) );
	toolbar->addAction( KStandardAction::revert( this, SLOT( selectNoLayout() ), actionCollection ) );

	//KDE4 port do the last arguments of the KToolBarPopupAction and line 67 duplicate information ?
	KToolBarPopupAction *shown_items = new KToolBarPopupAction( KIcon( "configure" ), i18n( "Items Shown" ), toolbar);
	shown_items->setDelayed( false );
	shown_items_popup = shown_items->menu();
	shown_items_popup->setTitle( i18n( "Show Items" ) );
	toolbar->addAction( shown_items );

	layout->addWidget( toolbar );

	QLabel *help = new QLabel(i18n("Usage: Select a template along the left, and right-click any element to edit the look of that element."),this);
	layout->addWidget( help );

	KHBox *viewBox = new KHBox( this );
	ThumbBarView *thumbBar = new ThumbBarView(viewBox,Qt::Horizontal);
	connect(thumbBar,SIGNAL(signalURLSelected(const QString&)), this, SLOT(loadTemplate(const QString&)));
	QDir included_templates( getIncludedLayoutDir(), "*.xsl", QDir::Name | QDir::IgnoreCase, QDir::Files );
	for ( uint i = 0; i < included_templates.count(); i++ ) {
		new ThumbBarItem(thumbBar,included_templates.path() + "/" +included_templates[ i ]);
	}
	m_htmlPart = new SetupDisplay(sample, viewBox);
	//m_htmlPart->view()->setParent( viewBox, windowFlags() & ~Qt::WindowType_Mask);
	//m_htmlPart->view()->setGeometry( 0, 0 ,m_htmlPart->view()->width(),m_htmlPart->view()->height());

	layout->addWidget( viewBox );

	KHBox *buttonsBox = new KHBox( this );
	QPushButton *okButton = new QPushButton( i18n( "Save and Close" ), buttonsBox );
	okButton->setIcon( KIcon( "dialog-ok" ) );
	QPushButton *cancelButton = new QPushButton( i18n( "&Cancel" ), buttonsBox );
	cancelButton->setIcon( KIcon( "dialog-cancel") );
	layout->addWidget( buttonsBox );

	connect( m_htmlPart, SIGNAL(itemVisibilityChanged(KreDisplayItem*,bool)), this, SLOT(updateItemVisibility(KreDisplayItem*,bool)) );
	connect( okButton, SIGNAL( clicked() ), SLOT( accept() ) );
	connect( cancelButton, SIGNAL( clicked() ), SLOT( reject() ) );

	KConfigGroup config = KGlobal::config()->group( "Page Setup" );
	QSize defaultSize(800,600);
	resize(config.readEntry( "WindowSize", defaultSize ));

	//let's do everything we can to be sure at least some layout is loaded
	QString layoutFile = config.readEntry( m_configEntry+"Layout", KStandardDirs::locate( "appdata", "layouts/None.klo" ) );
	if ( layoutFile.isEmpty() || !QFile::exists( layoutFile ) )
		layoutFile = KStandardDirs::locate( "appdata", "layouts/None.klo" );

	QString tmpl = config.readEntry( m_configEntry+"Template", KStandardDirs::locate( "appdata", "layouts/Default.xsl" ) );
	if ( tmpl.isEmpty() || !QFile::exists( tmpl ) )
		tmpl = KStandardDirs::locate( "appdata", "layouts/Default.xsl" );
	kDebug()<<"tmpl: "<<tmpl;
	active_template = tmpl;
	loadLayout( layoutFile );

	thumbBar->setSelected(thumbBar->findItemByURL(active_template));

	initShownItems();
}

void PageSetupDialog::accept()
{
	if ( m_htmlPart->hasChanges() )
		saveLayout();

	KConfigGroup config( KGlobal::config(), "Page Setup" );
	config.writeEntry( m_configEntry+"Layout", active_filename );

	if ( !active_template.isEmpty() ) {
		config.writeEntry( m_configEntry+"Template", active_template );
	}

	config.writeEntry( "WindowSize", size() );

	KDialog::accept();
}

void PageSetupDialog::reject()
{
	if ( m_htmlPart->hasChanges() ) {
		switch ( KMessageBox::questionYesNoCancel( this, i18n( "The recipe view layout has been modified.\nDo you want to save it?" ), i18n( "Save Layout?" ) ) ) {
		case KMessageBox::Yes:
			saveLayout();
			break;
		case KMessageBox::No:
			break;
		default:
			return ;
		}
	}

	KDialog::reject();
}

void PageSetupDialog::updateItemVisibility( KreDisplayItem *item, bool visible )
{
	shown_items_popup->setItemChecked( widget_popup_map[ item ], visible );
}

void PageSetupDialog::initShownItems()
{
	shown_items_popup->clear();

	PropertiesMap properties = m_htmlPart->properties();

	Q3ValueList<QString> nameList;
	QMap<QString,KreDisplayItem*> nameMap;

	for ( PropertiesMap::const_iterator it = properties.constBegin(); it != properties.constEnd(); ++it ) {
		nameList << it.key()->name;
		nameMap.insert( it.key()->name, it.key() );
	}
	qHeapSort( nameList );

	for ( Q3ValueList<QString>::const_iterator it = nameList.constBegin(); it != nameList.constEnd(); ++it ) {
		KreDisplayItem *item = nameMap[*it];
		if ( properties[item] & SetupDisplay::Visibility ) {
			int new_id = shown_items_popup->insertItem ( *it );
			shown_items_popup->setItemChecked( new_id, item->show );
			shown_items_popup->connectItem( new_id, this, SLOT( setItemShown( int ) ) );

			popup_widget_map.insert( new_id, item );
			widget_popup_map.insert( item, new_id );
		}
	}
}

void PageSetupDialog::setItemShown( int id )
{
	m_htmlPart->setItemShown( popup_widget_map[ id ], shown_items_popup->isItemChecked( id ) );
}

void PageSetupDialog::loadFile()
{
	QString file = KFileDialog::getOpenFileName( KStandardDirs::locateLocal( "appdata", "layouts/" ), QString("*.klo *.xsl|%1").arg(i18n("Krecipes style or template file")), this, i18n( "Select Layout" ) );

	if ( file.endsWith(".klo") )
		loadLayout( file );
	else {
		active_template = file;
		m_htmlPart->loadTemplate( file );
	}
}

void PageSetupDialog::loadLayout( int popup_param )
{
	loadLayout( getIncludedLayoutDir() + "/" + included_layouts_map[ popup_param ] );
}

void PageSetupDialog::loadTemplate( const QString& filename )
{
	active_template = filename;
	m_htmlPart->loadTemplate( active_template );
}

void PageSetupDialog::loadLayout( const QString &filename )
{
	if ( m_htmlPart->hasChanges() ) {
		switch ( KMessageBox::questionYesNoCancel( this, i18n( "This layout has been modified.\nDo you want to save it?" ), i18n( "Save Layout?" ) ) ) {
		case KMessageBox::Yes:
			saveLayout();
			break;
		case KMessageBox::No:
			break;
		default:
			return ;
		}
	}

	m_htmlPart->loadLayout( filename );
	setActiveFile( filename );
}

void PageSetupDialog::reloadLayout()
{
	m_htmlPart->reload();
}

void PageSetupDialog::saveLayout()
{
	if ( m_htmlPart->hasChanges() ) {
		if ( have_write_perm )
			m_htmlPart->saveLayout( active_filename );
		else {
			switch ( KMessageBox::warningYesNo( this, i18n( "Unable to save the layout because you do not have sufficient permissions to modify this file.\nWould you like to instead save the current layout to a new file?" ) ) ) {
			case KMessageBox::Yes:
				saveAsLayout();
				break;
			default:
				break;
			}
		}
	}
}

void PageSetupDialog::saveAsLayout()
{
	QString filename = KFileDialog::getSaveFileName( KGlobal::mainComponent().dirs() ->saveLocation( "appdata", "layouts/" ), "*.klo|Krecipes Layout (*.klo)", this, QString::null );

	if ( !filename.isEmpty() ) {
		if ( haveWritePerm( filename ) ) {
			m_htmlPart->saveLayout( filename );
			setActiveFile(filename);
		}
		else {
			switch ( KMessageBox::warningYesNo( this, i18n( "You have selected a file that you do not have the permissions to write to.\nWould you like to select another file?" ) ) ) {
			case KMessageBox::Yes:
				saveAsLayout();
				break;
			default:
				break;
			}
		}
	}
}

QString PageSetupDialog::getIncludedLayoutDir() const
{
	QFileInfo file_info( KStandardDirs::locate( "appdata", "layouts/None.klo" ) );
	return file_info.absolutePath();
}

void PageSetupDialog::setActiveFile( const QString &filename )
{
	active_filename = filename;
	have_write_perm = haveWritePerm( filename );
}

bool PageSetupDialog::haveWritePerm( const QString &filename )
{
	QFileInfo info( filename );

	if ( info.exists() )  //check that we can write to this particular file
	{
		QFileInfo info( filename );
		return info.isWritable();
	}
	else //check that we can write to the directory since the file doesn't exist
	{
		QFileInfo dir_info( info.absolutePath() );
		return dir_info.isWritable();
	}
}

void PageSetupDialog::selectNoLayout()
{
	m_htmlPart->loadLayout( QString::null );
	setActiveFile( QString::null );
//	QMap<int, KreDisplayItem*> popup_widget_map;
	QList<int> lst = popup_widget_map.uniqueKeys ();
	for (int i = 0; i < lst.size(); ++i)
	{
		shown_items_popup->setItemChecked(lst[i], true );
	}
}
#include "pagesetupdialog.moc"
<commit_msg>Fix Krazy warnings: doublequote_chars - src/dialogs/pagesetupdialog.cpp<commit_after>/***************************************************************************
*   Copyright © 2003-2005 Jason Kivlighn <jkivlighn@gmail.com>            *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
***************************************************************************/

#include "pagesetupdialog.h"

#include <QDir>

#include <QFileInfo>
#include <QPushButton>
#include <q3popupmenu.h>
#include <QLabel>
//Added by qt3to4:
#include <Q3ValueList>
#include <QVBoxLayout>
#include <q3tl.h>

#include <khtmlview.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kfiledialog.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kaction.h>
#include <kconfig.h>
#include <kstandardaction.h>
#include <ktoolbar.h>
#include <ktoolbarpopupaction.h>
#include <kmenu.h>
#include <KActionCollection>

#include <widgets/thumbbar.h>
#include <kglobal.h>
#include <kvbox.h>
#include "setupdisplay.h"

PageSetupDialog::PageSetupDialog( QWidget *parent, const Recipe &sample, const QString &configEntry )
	: KDialog( parent ), m_configEntry(configEntry)
{
	QWidget *w = new QWidget;
	QVBoxLayout * layout = new QVBoxLayout( this );
	w->setLayout( layout );
	setButtons( KDialog::None );
	setMainWidget( w );
	KToolBar *toolbar = new KToolBar( this );
	KActionCollection *actionCollection = new KActionCollection( this );
	setCaption( i18n("Page Setup") );

	toolbar->addAction( KStandardAction::open( this, SLOT(loadFile()), actionCollection ) );
	toolbar->addAction( KStandardAction::save( this, SLOT( saveLayout() ), actionCollection ) );
	toolbar->addAction( KStandardAction::saveAs( this, SLOT( saveAsLayout() ), actionCollection ) );
	toolbar->addAction( KStandardAction::revert( this, SLOT( selectNoLayout() ), actionCollection ) );

	//KDE4 port do the last arguments of the KToolBarPopupAction and line 67 duplicate information ?
	KToolBarPopupAction *shown_items = new KToolBarPopupAction( KIcon( "configure" ), i18n( "Items Shown" ), toolbar);
	shown_items->setDelayed( false );
	shown_items_popup = shown_items->menu();
	shown_items_popup->setTitle( i18n( "Show Items" ) );
	toolbar->addAction( shown_items );

	layout->addWidget( toolbar );

	QLabel *help = new QLabel(i18n("Usage: Select a template along the left, and right-click any element to edit the look of that element."),this);
	layout->addWidget( help );

	KHBox *viewBox = new KHBox( this );
	ThumbBarView *thumbBar = new ThumbBarView(viewBox,Qt::Horizontal);
	connect(thumbBar,SIGNAL(signalURLSelected(const QString&)), this, SLOT(loadTemplate(const QString&)));
	QDir included_templates( getIncludedLayoutDir(), "*.xsl", QDir::Name | QDir::IgnoreCase, QDir::Files );
	for ( uint i = 0; i < included_templates.count(); i++ ) {
		new ThumbBarItem(thumbBar,included_templates.path() + '/' +included_templates[ i ]);
	}
	m_htmlPart = new SetupDisplay(sample, viewBox);
	//m_htmlPart->view()->setParent( viewBox, windowFlags() & ~Qt::WindowType_Mask);
	//m_htmlPart->view()->setGeometry( 0, 0 ,m_htmlPart->view()->width(),m_htmlPart->view()->height());

	layout->addWidget( viewBox );

	KHBox *buttonsBox = new KHBox( this );
	QPushButton *okButton = new QPushButton( i18n( "Save and Close" ), buttonsBox );
	okButton->setIcon( KIcon( "dialog-ok" ) );
	QPushButton *cancelButton = new QPushButton( i18n( "&Cancel" ), buttonsBox );
	cancelButton->setIcon( KIcon( "dialog-cancel") );
	layout->addWidget( buttonsBox );

	connect( m_htmlPart, SIGNAL(itemVisibilityChanged(KreDisplayItem*,bool)), this, SLOT(updateItemVisibility(KreDisplayItem*,bool)) );
	connect( okButton, SIGNAL( clicked() ), SLOT( accept() ) );
	connect( cancelButton, SIGNAL( clicked() ), SLOT( reject() ) );

	KConfigGroup config = KGlobal::config()->group( "Page Setup" );
	QSize defaultSize(800,600);
	resize(config.readEntry( "WindowSize", defaultSize ));

	//let's do everything we can to be sure at least some layout is loaded
	QString layoutFile = config.readEntry( m_configEntry+"Layout", KStandardDirs::locate( "appdata", "layouts/None.klo" ) );
	if ( layoutFile.isEmpty() || !QFile::exists( layoutFile ) )
		layoutFile = KStandardDirs::locate( "appdata", "layouts/None.klo" );

	QString tmpl = config.readEntry( m_configEntry+"Template", KStandardDirs::locate( "appdata", "layouts/Default.xsl" ) );
	if ( tmpl.isEmpty() || !QFile::exists( tmpl ) )
		tmpl = KStandardDirs::locate( "appdata", "layouts/Default.xsl" );
	kDebug()<<"tmpl: "<<tmpl;
	active_template = tmpl;
	loadLayout( layoutFile );

	thumbBar->setSelected(thumbBar->findItemByURL(active_template));

	initShownItems();
}

void PageSetupDialog::accept()
{
	if ( m_htmlPart->hasChanges() )
		saveLayout();

	KConfigGroup config( KGlobal::config(), "Page Setup" );
	config.writeEntry( m_configEntry+"Layout", active_filename );

	if ( !active_template.isEmpty() ) {
		config.writeEntry( m_configEntry+"Template", active_template );
	}

	config.writeEntry( "WindowSize", size() );

	KDialog::accept();
}

void PageSetupDialog::reject()
{
	if ( m_htmlPart->hasChanges() ) {
		switch ( KMessageBox::questionYesNoCancel( this, i18n( "The recipe view layout has been modified.\nDo you want to save it?" ), i18n( "Save Layout?" ) ) ) {
		case KMessageBox::Yes:
			saveLayout();
			break;
		case KMessageBox::No:
			break;
		default:
			return ;
		}
	}

	KDialog::reject();
}

void PageSetupDialog::updateItemVisibility( KreDisplayItem *item, bool visible )
{
	shown_items_popup->setItemChecked( widget_popup_map[ item ], visible );
}

void PageSetupDialog::initShownItems()
{
	shown_items_popup->clear();

	PropertiesMap properties = m_htmlPart->properties();

	Q3ValueList<QString> nameList;
	QMap<QString,KreDisplayItem*> nameMap;

	for ( PropertiesMap::const_iterator it = properties.constBegin(); it != properties.constEnd(); ++it ) {
		nameList << it.key()->name;
		nameMap.insert( it.key()->name, it.key() );
	}
	qHeapSort( nameList );

	for ( Q3ValueList<QString>::const_iterator it = nameList.constBegin(); it != nameList.constEnd(); ++it ) {
		KreDisplayItem *item = nameMap[*it];
		if ( properties[item] & SetupDisplay::Visibility ) {
			int new_id = shown_items_popup->insertItem ( *it );
			shown_items_popup->setItemChecked( new_id, item->show );
			shown_items_popup->connectItem( new_id, this, SLOT( setItemShown( int ) ) );

			popup_widget_map.insert( new_id, item );
			widget_popup_map.insert( item, new_id );
		}
	}
}

void PageSetupDialog::setItemShown( int id )
{
	m_htmlPart->setItemShown( popup_widget_map[ id ], shown_items_popup->isItemChecked( id ) );
}

void PageSetupDialog::loadFile()
{
	QString file = KFileDialog::getOpenFileName( KStandardDirs::locateLocal( "appdata", "layouts/" ), QString("*.klo *.xsl|%1").arg(i18n("Krecipes style or template file")), this, i18n( "Select Layout" ) );

	if ( file.endsWith(".klo") )
		loadLayout( file );
	else {
		active_template = file;
		m_htmlPart->loadTemplate( file );
	}
}

void PageSetupDialog::loadLayout( int popup_param )
{
	loadLayout( getIncludedLayoutDir() + '/' + included_layouts_map[ popup_param ] );
}

void PageSetupDialog::loadTemplate( const QString& filename )
{
	active_template = filename;
	m_htmlPart->loadTemplate( active_template );
}

void PageSetupDialog::loadLayout( const QString &filename )
{
	if ( m_htmlPart->hasChanges() ) {
		switch ( KMessageBox::questionYesNoCancel( this, i18n( "This layout has been modified.\nDo you want to save it?" ), i18n( "Save Layout?" ) ) ) {
		case KMessageBox::Yes:
			saveLayout();
			break;
		case KMessageBox::No:
			break;
		default:
			return ;
		}
	}

	m_htmlPart->loadLayout( filename );
	setActiveFile( filename );
}

void PageSetupDialog::reloadLayout()
{
	m_htmlPart->reload();
}

void PageSetupDialog::saveLayout()
{
	if ( m_htmlPart->hasChanges() ) {
		if ( have_write_perm )
			m_htmlPart->saveLayout( active_filename );
		else {
			switch ( KMessageBox::warningYesNo( this, i18n( "Unable to save the layout because you do not have sufficient permissions to modify this file.\nWould you like to instead save the current layout to a new file?" ) ) ) {
			case KMessageBox::Yes:
				saveAsLayout();
				break;
			default:
				break;
			}
		}
	}
}

void PageSetupDialog::saveAsLayout()
{
	QString filename = KFileDialog::getSaveFileName( KGlobal::mainComponent().dirs() ->saveLocation( "appdata", "layouts/" ), "*.klo|Krecipes Layout (*.klo)", this, QString::null );

	if ( !filename.isEmpty() ) {
		if ( haveWritePerm( filename ) ) {
			m_htmlPart->saveLayout( filename );
			setActiveFile(filename);
		}
		else {
			switch ( KMessageBox::warningYesNo( this, i18n( "You have selected a file that you do not have the permissions to write to.\nWould you like to select another file?" ) ) ) {
			case KMessageBox::Yes:
				saveAsLayout();
				break;
			default:
				break;
			}
		}
	}
}

QString PageSetupDialog::getIncludedLayoutDir() const
{
	QFileInfo file_info( KStandardDirs::locate( "appdata", "layouts/None.klo" ) );
	return file_info.absolutePath();
}

void PageSetupDialog::setActiveFile( const QString &filename )
{
	active_filename = filename;
	have_write_perm = haveWritePerm( filename );
}

bool PageSetupDialog::haveWritePerm( const QString &filename )
{
	QFileInfo info( filename );

	if ( info.exists() )  //check that we can write to this particular file
	{
		QFileInfo info( filename );
		return info.isWritable();
	}
	else //check that we can write to the directory since the file doesn't exist
	{
		QFileInfo dir_info( info.absolutePath() );
		return dir_info.isWritable();
	}
}

void PageSetupDialog::selectNoLayout()
{
	m_htmlPart->loadLayout( QString::null );
	setActiveFile( QString::null );
//	QMap<int, KreDisplayItem*> popup_widget_map;
	QList<int> lst = popup_widget_map.uniqueKeys ();
	for (int i = 0; i < lst.size(); ++i)
	{
		shown_items_popup->setItemChecked(lst[i], true );
	}
}
#include "pagesetupdialog.moc"
<|endoftext|>


<commit_before>#ifndef PYTHONIC_NUMPY_NONZERO_HPP
#define PYTHONIC_NUMPY_NONZERO_HPP

#include "pythonic/include/numpy/nonzero.hpp"

#include "pythonic/utils/functor.hpp"
#include "pythonic/types/ndarray.hpp"

PYTHONIC_NS_BEGIN

namespace numpy
{

  namespace
  {
    template <class I, class O, size_t M>
    void _nonzero(I begin, I end, O &out, types::array<long, M> &curr,
                  utils::int_<1>)
    {
      I start = begin;
      for (; begin != end; ++begin) {
        curr[M - 1] = begin - start;
        if (*begin)
          for (size_t i = 0; i < M; ++i) {
            *(out[i]) = curr[i];
            ++out[i];
          }
      }
    }

    template <class I, class O, size_t M, size_t N>
    void _nonzero(I begin, I end, O &out, types::array<long, M> &curr,
                  utils::int_<N>)
    {
      I start = begin;
      for (; begin != end; ++begin) {
        curr[M - N] = begin - start;
        _nonzero((*begin).begin(), (*begin).end(), out, curr,
                 utils::int_<N - 1>());
      }
    }
  }

  template <size_t... Is>
  types::array<utils::shared_ref<types::raw_array<long>>, sizeof...(Is)>
  init_buffers(long sz, utils::index_sequence<Is...>)
  {
    return {{(Is, types::raw_array<long>(sz))...}}; // too much memory used
  }

  template <class E>
  auto nonzero(E const &expr)
      -> types::array<types::ndarray<long, types::array<long, 1>>, E::value>
  {
    constexpr long N = E::value;
    typedef types::array<types::ndarray<long, types::array<long, 1>>, E::value>
        out_type;
    long sz = expr.flat_size();

    types::array<utils::shared_ref<types::raw_array<long>>, N> out_buffers =
        init_buffers(sz, utils::make_index_sequence<N>());
    types::array<long *, N> out_iters;
    for (size_t i = 0; i < N; ++i)
      out_iters[i] = out_buffers[i]->data;

    types::array<long, N> indices;
    _nonzero(expr.begin(), expr.end(), out_iters, indices, utils::int_<N>());

    types::array<long, 1> shape = {{out_iters[0] - out_buffers[0]->data}};

    out_type out;
    for (size_t i = 0; i < N; ++i)
      out[i] = types::ndarray<long, types::array<long, 1>>(
          std::move(out_buffers[i]), shape);

    return out;
  }
}
PYTHONIC_NS_END

#endif
<commit_msg>Fix casting issue on windows<commit_after>#ifndef PYTHONIC_NUMPY_NONZERO_HPP
#define PYTHONIC_NUMPY_NONZERO_HPP

#include "pythonic/include/numpy/nonzero.hpp"

#include "pythonic/utils/functor.hpp"
#include "pythonic/types/ndarray.hpp"

PYTHONIC_NS_BEGIN

namespace numpy
{

  namespace
  {
    template <class I, class O, size_t M>
    void _nonzero(I begin, I end, O &out, types::array<long, M> &curr,
                  utils::int_<1>)
    {
      I start = begin;
      for (; begin != end; ++begin) {
        curr[M - 1] = begin - start;
        if (*begin)
          for (size_t i = 0; i < M; ++i) {
            *(out[i]) = curr[i];
            ++out[i];
          }
      }
    }

    template <class I, class O, size_t M, size_t N>
    void _nonzero(I begin, I end, O &out, types::array<long, M> &curr,
                  utils::int_<N>)
    {
      I start = begin;
      for (; begin != end; ++begin) {
        curr[M - N] = begin - start;
        _nonzero((*begin).begin(), (*begin).end(), out, curr,
                 utils::int_<N - 1>());
      }
    }
  }

  template <size_t... Is>
  types::array<utils::shared_ref<types::raw_array<long>>, sizeof...(Is)>
  init_buffers(long sz, utils::index_sequence<Is...>)
  {
    return {{(Is, types::raw_array<long>(sz))...}}; // too much memory used
  }

  template <class E>
  auto nonzero(E const &expr)
      -> types::array<types::ndarray<long, types::array<long, 1>>, E::value>
  {
    constexpr long N = E::value;
    typedef types::array<types::ndarray<long, types::array<long, 1>>, E::value>
        out_type;
    long sz = expr.flat_size();

    types::array<utils::shared_ref<types::raw_array<long>>, N> out_buffers =
        init_buffers(sz, utils::make_index_sequence<N>());
    types::array<long *, N> out_iters;
    for (size_t i = 0; i < N; ++i)
      out_iters[i] = out_buffers[i]->data;

    types::array<long, N> indices;
    _nonzero(expr.begin(), expr.end(), out_iters, indices, utils::int_<N>());

    types::array<long, 1> shape = {
        {(long)(out_iters[0] - out_buffers[0]->data)}};

    out_type out;
    for (size_t i = 0; i < N; ++i)
      out[i] = types::ndarray<long, types::array<long, 1>>(
          std::move(out_buffers[i]), shape);

    return out;
  }
}
PYTHONIC_NS_END

#endif
<|endoftext|>


<commit_before>
#include <cstdlib>
#include <cstdio>
#include <cmath>

#include <array>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>

using namespace std;

#include <mpi.h>

// simulation constants
const double l = 256.0;
const long n = 2560;
const long np = n*n*n;
const double dx = l / n;

std::vector<std::string>
split_string(const std::string str, const char split_char)
{
    // make return obj
    std::vector<std::string> result;

    // split and push each back to result.
    std::stringstream str_stream(str);
    std::string element;
    while(std::getline(str_stream, element, split_char))
    {
        result.push_back(element);
    }

    return result;
}

std::vector< std::array<double, 3> >
read_centers(const std::string path)
{
    // Prep return value.
    std::vector< std::array<double, 3> > centers;

    // Open and check file.
    std::ifstream centers_file(path.c_str());
    if (centers_file.is_open()) {
        // line obj to read into.
        std::string line;

        // read past headers
        std::getline(centers_file, line);

        // now read for centers and push onto return vec.
        while (std::getline(centers_file, line)) {
            std::vector<std::string> t = split_string(line, ',');

            // TODO
            // hard coding position indexes for now.
            std::array<double, 3> c = {stod(t[0]), stod(t[1]), stod(t[2])};
            // DEBUG
            // just to be safe...
            if (c[0] < 0.0 || c[0] >= l || c[1] < 0.0 || c[1] >= l
                || c[2] < 0.0 || c[2] >= l) {
                std::cerr << "bad position: " << c[0] << " " << c[1] << " " << c[2] << std::endl;
                exit(1);
            }

            centers.push_back(c);
        }
    }
    else {
        std::cerr << "Could not read " << path << std::endl;
        exit(1);
    }

    return centers;
}

int
main(int argc, char **argv)
{
    // Initialize MPI stuff
    MPI_Init(&argc, &argv);
    MPI_Comm comm = MPI_COMM_WORLD;
    int mpi_size, mpi_rank;
    MPI_Comm_size(comm, &mpi_size);
    MPI_Comm_rank(comm, &mpi_rank);
    int master_rank = 0;

    // command line
    const std::string centers_path = argv[1];
    const std::string field_path = argv[2];
    const std::string pre_path = argv[3];

    // figure out decomp.
    if (n % mpi_size != 0) {
        printf("Bad mpi size %i for grid %li\n", mpi_size, n);
    }

    //
    // Read halo positions.
    //

    if (mpi_rank == 0) {
        printf("# Reading centers %s\n", centers_path.c_str());
    }

    vector< array<double, 3> > centers = read_centers(centers_path);

    if (mpi_rank == 0) {
        printf("# Found %lu centers\n", centers.size());
    }

    //
    // Read field values.
    //

    if (mpi_rank == 0) {
        printf("# Reading %s\n", field_path.c_str());
    }

    const long n_local = n / mpi_size;
    const long np_local = n_local * n * n;
    const long local_ix0 = mpi_rank * n_local;

    double *f = new double[np_local];

    FILE *field_file = fopen(field_path.c_str(), "r");
    fseek(field_file, sizeof(double) * local_ix0 * n * n, SEEK_SET);
    fread(f, sizeof(double), np_local, field_file);
    fclose(field_file);

    //
    // Compute field mean and variance.
    //

    double f_sum_local = 0.0;
    double f2_sum_local = 0.0;

    for (long i = 0; i < np_local; ++i) {
        f_sum_local += f[i];
        f2_sum_local += f[i]*f[i];
    }

    double f_sum;
    MPI_Allreduce(&f_sum_local, &f_sum, 1, MPI_DOUBLE, MPI_SUM, comm);
    double f2_sum;
    MPI_Allreduce(&f2_sum_local, &f2_sum, 1, MPI_DOUBLE, MPI_SUM, comm);

    double f_mean = f_sum / np;
    double f2_mean = f2_sum / np;

    if (mpi_rank == master_rank) {
        char output_path[1000];
        sprintf(output_path, "%sfield_var.txt", pre_path.c_str());
        FILE *outfile = fopen(output_path, "w");
        fprintf(outfile, "%e %e\n", f_mean, sqrt(f2_mean - f_mean * f_mean));
        fclose(outfile);
    }

    //
    // start accumulating radial bins
    //

    if (mpi_rank == 0) { puts("# Finding local halos."); }

    // 10 Mpc/h in 256 Mpc/h
    const double r_max = 20.0;
    const int num_bins = 100;
    const double bin_dr = r_max / num_bins;

    long *bin_counts_local = new long[num_bins];
    long *bin_counts = new long[num_bins];
    double *bin_f_sums_local = new double[num_bins];
    double *bin_f_sums = new double[num_bins];
    double *bin_fr_sums_local = new double[num_bins];
    double *bin_fr_sums = new double[num_bins];

    // iterate over groups
    for (size_t i_cent = 0; i_cent < centers.size(); ++i_cent) {
        // reset local stuff
        for (int i = 0; i < num_bins; ++i) {
            bin_counts_local[i] = 0;
            bin_f_sums_local[i] = 0.0;
            bin_fr_sums_local[i] = 0.0;
        }

        // get pc position
        double cx = centers[i_cent][0];
        double cy = centers[i_cent][1];
        double cz = centers[i_cent][2];

        long ix0 = floor( (cx - r_max) / dx );
        long ix1 = ceil( (cx + r_max) / dx );
        long iy0 = floor( (cy - r_max) / dx );
        long iy1 = ceil( (cy + r_max) / dx );
        long iz0 = floor( (cz - r_max) / dx );
        long iz1 = ceil( (cz + r_max) / dx );

        // iterate over points.
        for (long ix = ix0; ix <= ix1; ++ix) {
            // periodic fix
            long ixw = ix;
            if (ixw < 0) { ixw += n; }
            if (ixw >= n) { ixw -= n; }

            long ix_local = ixw - local_ix0;

            // check if this is even local before continuing.
            if (ix_local >= 0 && ix_local < n_local) {
                double x = dx * (ix + 0.5);
                double drx = x - cx;
                double drx2 = drx * drx;

                for (long iy = iy0; iy <= iy1; ++iy) {
                    long iyw = iy;
                    if (iyw < 0) { iyw += n; }
                    if (iyw >= n) { iyw -= n; }

                    double y = dx * (iy + 0.5);
                    double dry = y - cy;
                    double drxy2 = drx2 + dry * dry;

                    for (long iz = iz0; iz <= iz1; ++iz) {
                        long izw = iz;
                        if (izw < 0) { izw += n; }
                        if (izw >= n) { izw -= n; }

                        double z = dx * (iz + 0.5);
                        double drz = z - cz;
                        double r = sqrt(drxy2 + drz * drz);
                        int ibin = r / bin_dr;

                        if (ibin < num_bins) {
                            // got a bin point
                            long ii = (ix_local * n + iyw) * n + izw;
                            bin_counts_local[ibin] += 1;
                            bin_f_sums_local[ibin] += f[ii];
                            bin_fr_sums_local[ibin] += f[ii] * r;
                        }
                    }
                }
            }
        }

        // done with binning for this PC.
        MPI_Allreduce(bin_counts_local, bin_counts, num_bins, MPI_LONG, MPI_SUM, comm);
        MPI_Allreduce(bin_f_sums_local, bin_f_sums, num_bins, MPI_DOUBLE, MPI_SUM, comm);
        MPI_Allreduce(bin_fr_sums_local, bin_fr_sums, num_bins, MPI_DOUBLE, MPI_SUM, comm);

        // write this pc.
        // make sure file is empty
        if (mpi_rank == 0) {
            char output_path[1000];
            sprintf(output_path, "%sprofile_%06d.txt", pre_path.c_str(), (int)i_cent);
            FILE *outfile = fopen(output_path, "w");
            fprintf(outfile, "radius,field_value\n");
            for (int i = 0; i < num_bins; ++i) {
                if (bin_counts[i] > 0) {
                    fprintf(outfile, "%e,%e\n",
                        bin_fr_sums[i] / bin_f_sums[i],
                        bin_f_sums[i] / bin_counts[i]);
                }
                else {
                    fprintf(outfile, "0.0,0.0\n");
                }
            }
            fclose(outfile);
        }

        // done with this center
    }

    MPI_Finalize();
    return 0;
}
<commit_msg>radial profiles: fix f(r) binning to work for negative fields.<commit_after>
#include <cstdlib>
#include <cstdio>
#include <cmath>

#include <array>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>

using namespace std;

#include <mpi.h>

// simulation constants
const double l = 256.0;
const long n = 2560;
const long np = n*n*n;
const double dx = l / n;

std::vector<std::string>
split_string(const std::string str, const char split_char)
{
    // make return obj
    std::vector<std::string> result;

    // split and push each back to result.
    std::stringstream str_stream(str);
    std::string element;
    while(std::getline(str_stream, element, split_char))
    {
        result.push_back(element);
    }

    return result;
}

std::vector< std::array<double, 3> >
read_centers(const std::string path)
{
    // Prep return value.
    std::vector< std::array<double, 3> > centers;

    // Open and check file.
    std::ifstream centers_file(path.c_str());
    if (centers_file.is_open()) {
        // line obj to read into.
        std::string line;

        // read past headers
        std::getline(centers_file, line);

        // now read for centers and push onto return vec.
        while (std::getline(centers_file, line)) {
            std::vector<std::string> t = split_string(line, ',');

            // TODO
            // hard coding position indexes for now.
            std::array<double, 3> c = {stod(t[0]), stod(t[1]), stod(t[2])};
            // DEBUG
            // just to be safe...
            if (c[0] < 0.0 || c[0] >= l || c[1] < 0.0 || c[1] >= l
                || c[2] < 0.0 || c[2] >= l) {
                std::cerr << "bad position: " << c[0] << " " << c[1] << " " << c[2] << std::endl;
                exit(1);
            }

            centers.push_back(c);
        }
    }
    else {
        std::cerr << "Could not read " << path << std::endl;
        exit(1);
    }

    return centers;
}

int
main(int argc, char **argv)
{
    // Initialize MPI stuff
    MPI_Init(&argc, &argv);
    MPI_Comm comm = MPI_COMM_WORLD;
    int mpi_size, mpi_rank;
    MPI_Comm_size(comm, &mpi_size);
    MPI_Comm_rank(comm, &mpi_rank);
    int master_rank = 0;

    // command line
    const std::string centers_path = argv[1];
    const std::string field_path = argv[2];
    const std::string pre_path = argv[3];

    // figure out decomp.
    if (n % mpi_size != 0) {
        printf("Bad mpi size %i for grid %li\n", mpi_size, n);
    }

    //
    // Read halo positions.
    //

    if (mpi_rank == 0) {
        printf("# Reading centers %s\n", centers_path.c_str());
    }

    vector< array<double, 3> > centers = read_centers(centers_path);

    if (mpi_rank == 0) {
        printf("# Found %lu centers\n", centers.size());
    }

    //
    // Read field values.
    //

    if (mpi_rank == 0) {
        printf("# Reading %s\n", field_path.c_str());
    }

    const long n_local = n / mpi_size;
    const long np_local = n_local * n * n;
    const long local_ix0 = mpi_rank * n_local;

    double *f = new double[np_local];

    FILE *field_file = fopen(field_path.c_str(), "r");
    fseek(field_file, sizeof(double) * local_ix0 * n * n, SEEK_SET);
    fread(f, sizeof(double), np_local, field_file);
    fclose(field_file);

    //
    // Compute field mean and variance.
    //

    double f_sum_local = 0.0;
    double f2_sum_local = 0.0;

    for (long i = 0; i < np_local; ++i) {
        f_sum_local += f[i];
        f2_sum_local += f[i]*f[i];
    }

    double f_sum;
    MPI_Allreduce(&f_sum_local, &f_sum, 1, MPI_DOUBLE, MPI_SUM, comm);
    double f2_sum;
    MPI_Allreduce(&f2_sum_local, &f2_sum, 1, MPI_DOUBLE, MPI_SUM, comm);

    double f_mean = f_sum / np;
    double f2_mean = f2_sum / np;

    if (mpi_rank == master_rank) {
        char output_path[1000];
        sprintf(output_path, "%sfield_var.txt", pre_path.c_str());
        FILE *outfile = fopen(output_path, "w");
        fprintf(outfile, "%e %e\n", f_mean, sqrt(f2_mean - f_mean * f_mean));
        fclose(outfile);
    }

    //
    // start accumulating radial bins
    //

    if (mpi_rank == 0) { puts("# Finding local halos."); }

    // 10 Mpc/h in 256 Mpc/h
    const double r_max = 20.0;
    const int num_bins = 100;
    const double bin_dr = r_max / num_bins;

    long *bin_counts_local = new long[num_bins];
    long *bin_counts = new long[num_bins];
    double *bin_f_sums_local = new double[num_bins];
    double *bin_f_sums = new double[num_bins];
    double *bin_r_sums_local = new double[num_bins];
    double *bin_r_sums = new double[num_bins];

    // iterate over groups
    for (size_t i_cent = 0; i_cent < centers.size(); ++i_cent) {
        // reset local stuff
        for (int i = 0; i < num_bins; ++i) {
            bin_counts_local[i] = 0;
            bin_f_sums_local[i] = 0.0;
            bin_r_sums_local[i] = 0.0;
        }

        // get pc position
        double cx = centers[i_cent][0];
        double cy = centers[i_cent][1];
        double cz = centers[i_cent][2];

        long ix0 = floor( (cx - r_max) / dx );
        long ix1 = ceil( (cx + r_max) / dx );
        long iy0 = floor( (cy - r_max) / dx );
        long iy1 = ceil( (cy + r_max) / dx );
        long iz0 = floor( (cz - r_max) / dx );
        long iz1 = ceil( (cz + r_max) / dx );

        // iterate over points.
        for (long ix = ix0; ix <= ix1; ++ix) {
            // periodic fix
            long ixw = ix;
            if (ixw < 0) { ixw += n; }
            if (ixw >= n) { ixw -= n; }

            long ix_local = ixw - local_ix0;

            // check if this is even local before continuing.
            if (ix_local >= 0 && ix_local < n_local) {
                double x = dx * (ix + 0.5);
                double drx = x - cx;
                double drx2 = drx * drx;

                for (long iy = iy0; iy <= iy1; ++iy) {
                    long iyw = iy;
                    if (iyw < 0) { iyw += n; }
                    if (iyw >= n) { iyw -= n; }

                    double y = dx * (iy + 0.5);
                    double dry = y - cy;
                    double drxy2 = drx2 + dry * dry;

                    for (long iz = iz0; iz <= iz1; ++iz) {
                        long izw = iz;
                        if (izw < 0) { izw += n; }
                        if (izw >= n) { izw -= n; }

                        double z = dx * (iz + 0.5);
                        double drz = z - cz;
                        double r = sqrt(drxy2 + drz * drz);
                        int ibin = r / bin_dr;

                        if (ibin < num_bins) {
                            // got a bin point
                            long ii = (ix_local * n + iyw) * n + izw;
                            bin_counts_local[ibin] += 1;
                            bin_f_sums_local[ibin] += f[ii];
                            bin_r_sums_local[ibin] += r;
                        }
                    }
                }
            }
        }

        // done with binning for this PC.
        MPI_Allreduce(bin_counts_local, bin_counts, num_bins, MPI_LONG, MPI_SUM, comm);
        MPI_Allreduce(bin_f_sums_local, bin_f_sums, num_bins, MPI_DOUBLE, MPI_SUM, comm);
        MPI_Allreduce(bin_r_sums_local, bin_r_sums, num_bins, MPI_DOUBLE, MPI_SUM, comm);

        // write this pc.
        // make sure file is empty
        if (mpi_rank == 0) {
            char output_path[1000];
            sprintf(output_path, "%sprofile_%06d.txt", pre_path.c_str(), (int)i_cent);
            FILE *outfile = fopen(output_path, "w");
            fprintf(outfile, "radius,field_value\n");
            for (int i = 0; i < num_bins; ++i) {
                if (bin_counts[i] > 0) {
                    fprintf(outfile, "%e,%e\n",
                        bin_r_sums[i] / bin_counts[i],
                        bin_f_sums[i] / bin_counts[i]);
                }
                else {
                    fprintf(outfile, "0.0,0.0\n");
                }
            }
            fclose(outfile);
        }

        // done with this center
    }

    MPI_Finalize();
    return 0;
}
<|endoftext|>


<commit_before>#ifndef UTIL_RECT_H__
#define UTIL_RECT_H__

#include <sstream>
#include <iostream>

#include "point.hpp"

namespace util {

template <typename T>
struct rect {

	/**
	 * Default constructor.
	 */
	rect() {};

	template <typename S>
	rect(const rect<S>& other) :
		minX(other.minX),
		minY(other.minY),
		maxX(other.maxX),
		maxY(other.maxY) {};

	rect(const T& minX_, const T& minY_, const T& maxX_, const T& maxY_) :
		minX(minX_),
		minY(minY_),
		maxX(maxX_),
		maxY(maxY_) {};

	T minX;
	T minY;
	T maxX;
	T maxY;

	T width() const {

		return maxX - minX;
	}

	T height() const {

		return maxY - minY;
	}

	point<T> upperLeft() const {

		return point<T>(minX, minY);
	}

	point<T> lowerRight() const {

		return point<T>(maxX, maxY);
	}

	point<T> upperRight() const {

		return point<T>(maxX, minY);
	}

	point<T> lowerLeft() const {

		return point<T>(minX, maxY);
	}

	point<T> center() const {

		return point<T>((minX + maxX)/2, (minY + maxY)/2);
	}

	bool intersects(const rect<T>& other) const {

		// two non-intersecting rectanlges are separated by a line parallel to
		// either x or y

		// separated by x-line
		if (maxX < other.minX || minX > other.maxX)
			return false;

		// separated by y-line
		if (maxY < other.minY || minY > other.maxY)
			return false;

		return true;
	}

	rect<T> intersection(const rect<T>& other) const {

		rect<T> result(0, 0, 0, 0);

		if (!intersects(other))
			return result;

		result.minX = std::max(minX, other.minX);
		result.minY = std::max(minY, other.minY);
		result.maxX = std::min(maxX, other.maxX);
		result.maxY = std::min(maxY, other.maxY);

		return result;
	}

	bool contains(const point<T>& point) const {

		return minX <= point.x && minY <= point.y && maxX > point.x && maxY > point.y;
	}

	T area() const {

		return width()*height();
	}

	template <typename S>
	rect<T>& operator+=(const point<S>& other) {

		minX += other.x;
		maxX += other.x;
		minY += other.y;
		maxY += other.y;

		return *this;
	}

	template <typename S>
	rect<T>& operator-=(const point<S>& other) {

		minX -= other.x;
		maxX -= other.x;
		minY -= other.y;
		maxY -= other.y;

		return *this;
	}

	template <typename S>
	rect<T>& operator*=(const S& s) {

		minX *= s;
		maxX *= s;
		minY *= s;
		maxY *= s;

		return *this;
	}

	template <typename S>
	rect<T>& operator/=(const S& s) {

		minX /= s;
		maxX /= s;
		minY /= s;
		maxY /= s;

		return *this;
	}

	template <typename S>
	rect<T>& operator*=(const point<S>& p) {

		minX *= p.x;
		maxX *= p.x;
		minY *= p.y;
		maxY *= p.y;

		return *this;
	}

	template <typename S>
	rect<T>& operator/=(const point<S>& p) {

		minX /= p.x;
		maxX /= p.x;
		minY /= p.y;
		maxY /= p.y;

		return *this;
	}

	template <typename S>
	bool operator==(const rect<S>& other) const {

		return minX == other.minX &&
		       minY == other.minY &&
		       maxX == other.maxX &&
		       maxY == other.maxY;
	}

	template <typename S>
	bool operator!=(const rect<S>& other) const {

		return !(*this == other);
	}
};

} // namespace util

template <typename T, typename S>
util::rect<T> operator+(const util::rect<T>& p, const util::point<S>& o) {

	util::rect<T> result(p);

	return result += o;
}

template <typename T, typename S>
util::rect<T> operator-(const util::rect<T>& p, const util::point<S>& o) {

	util::rect<T> result(p);

	return result -= o;
}

template <typename T, typename S>
util::rect<T> operator*(const util::rect<T>& p, const S& s) {

	util::rect<T> result(p);

	return result *= s;
}

template <typename T, typename S>
util::rect<S> operator*(const S& s, const util::rect<T>& p) {

	util::rect<S> result(p);

	return result *= s;
}

template <typename T, typename S>
util::rect<T> operator/(const util::rect<T>& p, const S& s) {

	util::rect<T> result(p);

	return result /= s;
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const util::rect<T>& rect) {

	os << "[" << rect.minX << ", " << rect.minY
	   << ", " << rect.maxX << ", " << rect.maxY << "]";

	return os;
}

#endif // UTIL_RECT_H__

<commit_msg>fixed intersect() in rect: max{X,Y} are not part of the rectangle, zero-size rectangles don't intersect with anyone<commit_after>#ifndef UTIL_RECT_H__
#define UTIL_RECT_H__

#include <sstream>
#include <iostream>

#include "point.hpp"

namespace util {

template <typename T>
struct rect {

	/**
	 * Default constructor.
	 */
	rect() {};

	template <typename S>
	rect(const rect<S>& other) :
		minX(other.minX),
		minY(other.minY),
		maxX(other.maxX),
		maxY(other.maxY) {};

	rect(const T& minX_, const T& minY_, const T& maxX_, const T& maxY_) :
		minX(minX_),
		minY(minY_),
		maxX(maxX_),
		maxY(maxY_) {};

	T minX;
	T minY;
	T maxX;
	T maxY;

	T width() const {

		return maxX - minX;
	}

	T height() const {

		return maxY - minY;
	}

	point<T> upperLeft() const {

		return point<T>(minX, minY);
	}

	point<T> lowerRight() const {

		return point<T>(maxX, maxY);
	}

	point<T> upperRight() const {

		return point<T>(maxX, minY);
	}

	point<T> lowerLeft() const {

		return point<T>(minX, maxY);
	}

	point<T> center() const {

		return point<T>((minX + maxX)/2, (minY + maxY)/2);
	}

	bool intersects(const rect<T>& other) const {

		// empty rectangles do not intersect
		if (area()*other.area() == 0)
			return false;

		// two non-intersecting rectanlges are separated by a line parallel to
		// either x or y

		// separated by x-line
		if (maxX <= other.minX || minX >= other.maxX)
			return false;

		// separated by y-line
		if (maxY <= other.minY || minY >= other.maxY)
			return false;

		return true;
	}

	rect<T> intersection(const rect<T>& other) const {

		rect<T> result(0, 0, 0, 0);

		if (!intersects(other))
			return result;

		result.minX = std::max(minX, other.minX);
		result.minY = std::max(minY, other.minY);
		result.maxX = std::min(maxX, other.maxX);
		result.maxY = std::min(maxY, other.maxY);

		return result;
	}

	bool contains(const point<T>& point) const {

		return minX <= point.x && minY <= point.y && maxX > point.x && maxY > point.y;
	}

	T area() const {

		return width()*height();
	}

	template <typename S>
	rect<T>& operator+=(const point<S>& other) {

		minX += other.x;
		maxX += other.x;
		minY += other.y;
		maxY += other.y;

		return *this;
	}

	template <typename S>
	rect<T>& operator-=(const point<S>& other) {

		minX -= other.x;
		maxX -= other.x;
		minY -= other.y;
		maxY -= other.y;

		return *this;
	}

	template <typename S>
	rect<T>& operator*=(const S& s) {

		minX *= s;
		maxX *= s;
		minY *= s;
		maxY *= s;

		return *this;
	}

	template <typename S>
	rect<T>& operator/=(const S& s) {

		minX /= s;
		maxX /= s;
		minY /= s;
		maxY /= s;

		return *this;
	}

	template <typename S>
	rect<T>& operator*=(const point<S>& p) {

		minX *= p.x;
		maxX *= p.x;
		minY *= p.y;
		maxY *= p.y;

		return *this;
	}

	template <typename S>
	rect<T>& operator/=(const point<S>& p) {

		minX /= p.x;
		maxX /= p.x;
		minY /= p.y;
		maxY /= p.y;

		return *this;
	}

	template <typename S>
	bool operator==(const rect<S>& other) const {

		return minX == other.minX &&
		       minY == other.minY &&
		       maxX == other.maxX &&
		       maxY == other.maxY;
	}

	template <typename S>
	bool operator!=(const rect<S>& other) const {

		return !(*this == other);
	}
};

} // namespace util

template <typename T, typename S>
util::rect<T> operator+(const util::rect<T>& p, const util::point<S>& o) {

	util::rect<T> result(p);

	return result += o;
}

template <typename T, typename S>
util::rect<T> operator-(const util::rect<T>& p, const util::point<S>& o) {

	util::rect<T> result(p);

	return result -= o;
}

template <typename T, typename S>
util::rect<T> operator*(const util::rect<T>& p, const S& s) {

	util::rect<T> result(p);

	return result *= s;
}

template <typename T, typename S>
util::rect<S> operator*(const S& s, const util::rect<T>& p) {

	util::rect<S> result(p);

	return result *= s;
}

template <typename T, typename S>
util::rect<T> operator/(const util::rect<T>& p, const S& s) {

	util::rect<T> result(p);

	return result /= s;
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const util::rect<T>& rect) {

	os << "[" << rect.minX << ", " << rect.minY
	   << ", " << rect.maxX << ", " << rect.maxY << "]";

	return os;
}

#endif // UTIL_RECT_H__

<|endoftext|>