<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkColorSpaceXform_Base.h"
#include "SkColorSpaceXformPriv.h"
#include "SkColorTable.h"
#include "SkConvertPixels.h"
#include "SkHalf.h"
#include "SkImageInfoPriv.h"
#include "SkOpts.h"
#include "SkPM4fPriv.h"
#include "SkRasterPipeline.h"
#include "SkUnPreMultiply.h"
#include "SkUnPreMultiplyPriv.h"
#include "../jumper/SkJumper.h"

// Fast Path 1: The memcpy() case.
static inline bool can_memcpy(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
    if (dstInfo.colorType() != srcInfo.colorType()) {
        return false;
    }

    if (kAlpha_8_SkColorType == dstInfo.colorType()) {
        return true;
    }

    if (dstInfo.alphaType() != srcInfo.alphaType() &&
        kOpaque_SkAlphaType != dstInfo.alphaType() &&
        kOpaque_SkAlphaType != srcInfo.alphaType())
    {
        // We need to premultiply or unpremultiply.
        return false;
    }

    return !dstInfo.colorSpace() ||
           SkColorSpace::Equals(dstInfo.colorSpace(), srcInfo.colorSpace());
}

// Fast Path 2: Simple swizzles and premuls.
enum AlphaVerb {
    kNothing_AlphaVerb,
    kPremul_AlphaVerb,
    kUnpremul_AlphaVerb,
};

template <bool kSwapRB>
static void wrap_unpremultiply(uint32_t* dst, const void* src, int count) {
    SkUnpremultiplyRow<kSwapRB>(dst, (const uint32_t*) src, count);
}

void swizzle_and_multiply(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
                          const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) {
    void (*proc)(uint32_t* dst, const void* src, int count);
    const bool swapRB = dstInfo.colorType() != srcInfo.colorType();
    AlphaVerb alphaVerb = kNothing_AlphaVerb;
    if (kPremul_SkAlphaType == dstInfo.alphaType() &&
        kUnpremul_SkAlphaType == srcInfo.alphaType())
    {
        alphaVerb = kPremul_AlphaVerb;
    } else if (kUnpremul_SkAlphaType == dstInfo.alphaType() &&
               kPremul_SkAlphaType == srcInfo.alphaType()) {
        alphaVerb = kUnpremul_AlphaVerb;
    }

    switch (alphaVerb) {
        case kNothing_AlphaVerb:
            // If we do not need to swap or multiply, we should hit the memcpy case.
            SkASSERT(swapRB);
            proc = SkOpts::RGBA_to_BGRA;
            break;
        case kPremul_AlphaVerb:
            proc = swapRB ? SkOpts::RGBA_to_bgrA : SkOpts::RGBA_to_rgbA;
            break;
        case kUnpremul_AlphaVerb:
            proc = swapRB ? wrap_unpremultiply<true> : wrap_unpremultiply<false>;
            break;
    }

    for (int y = 0; y < dstInfo.height(); y++) {
        proc((uint32_t*) dstPixels, srcPixels, dstInfo.width());
        dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
        srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
    }
}

// Fast Path 3: Alpha 8 dsts.
static void convert_to_alpha8(uint8_t* dst, size_t dstRB, const SkImageInfo& srcInfo,
                              const void* src, size_t srcRB, SkColorTable* ctable) {
    if (srcInfo.isOpaque()) {
        for (int y = 0; y < srcInfo.height(); ++y) {
           memset(dst, 0xFF, srcInfo.width());
           dst = SkTAddOffset<uint8_t>(dst, dstRB);
        }
        return;
    }

    switch (srcInfo.colorType()) {
        case kBGRA_8888_SkColorType:
        case kRGBA_8888_SkColorType: {
            auto src32 = (const uint32_t*) src;
            for (int y = 0; y < srcInfo.height(); y++) {
                for (int x = 0; x < srcInfo.width(); x++) {
                    dst[x] = src32[x] >> 24;
                }
                dst = SkTAddOffset<uint8_t>(dst, dstRB);
                src32 = SkTAddOffset<const uint32_t>(src32, srcRB);
            }
            break;
        }
        case kARGB_4444_SkColorType: {
            auto src16 = (const uint16_t*) src;
            for (int y = 0; y < srcInfo.height(); y++) {
                for (int x = 0; x < srcInfo.width(); x++) {
                    dst[x] = SkPacked4444ToA32(src16[x]);
                }
                dst = SkTAddOffset<uint8_t>(dst, dstRB);
                src16 = SkTAddOffset<const uint16_t>(src16, srcRB);
            }
            break;
        }
        case kRGBA_F16_SkColorType: {
            auto src64 = (const uint64_t*) src;
            for (int y = 0; y < srcInfo.height(); y++) {
                for (int x = 0; x < srcInfo.width(); x++) {
                    dst[x] = (uint8_t) (255.0f * SkHalfToFloat(src64[x] >> 48));
                }
                dst = SkTAddOffset<uint8_t>(dst, dstRB);
                src64 = SkTAddOffset<const uint64_t>(src64, srcRB);
            }
            break;
        }
        default:
            SkASSERT(false);
            break;
    }
}

// Default: Use the pipeline.
static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB,
                                  const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB,
                                  bool isColorAware, SkTransferFunctionBehavior behavior) {

    SkJumper_MemoryCtx src = { (void*)srcRow, (int)(srcRB / srcInfo.bytesPerPixel()) },
                       dst = { (void*)dstRow, (int)(dstRB / dstInfo.bytesPerPixel()) };

    SkRasterPipeline_<256> pipeline;
    switch (srcInfo.colorType()) {
        case kRGBA_8888_SkColorType:
            pipeline.append(SkRasterPipeline::load_8888, &src);
            break;
        case kBGRA_8888_SkColorType:
            pipeline.append(SkRasterPipeline::load_bgra, &src);
            break;
        case kRGB_565_SkColorType:
            pipeline.append(SkRasterPipeline::load_565, &src);
            break;
        case kRGBA_F16_SkColorType:
            pipeline.append(SkRasterPipeline::load_f16, &src);
            break;
        case kGray_8_SkColorType:
            pipeline.append(SkRasterPipeline::load_g8, &src);
            break;
        case kARGB_4444_SkColorType:
            pipeline.append(SkRasterPipeline::load_4444, &src);
            break;
        default:
            SkASSERT(false);
            break;
    }

    SkAlphaType premulState = srcInfo.alphaType();
    if (kPremul_SkAlphaType == premulState && SkTransferFunctionBehavior::kIgnore == behavior) {
        pipeline.append(SkRasterPipeline::unpremul);
        premulState = kUnpremul_SkAlphaType;
    }

    SkColorSpaceTransferFn srcFn;
    if (isColorAware && srcInfo.gammaCloseToSRGB()) {
        pipeline.append_from_srgb(premulState);
    } else if (isColorAware && !srcInfo.colorSpace()->gammaIsLinear()) {
        SkAssertResult(srcInfo.colorSpace()->isNumericalTransferFn(&srcFn));
        pipeline.append(SkRasterPipeline::parametric_r, &srcFn);
        pipeline.append(SkRasterPipeline::parametric_g, &srcFn);
        pipeline.append(SkRasterPipeline::parametric_b, &srcFn);
    }

    float matrix[12];
    if (isColorAware) {
        append_gamut_transform(&pipeline, matrix, srcInfo.colorSpace(), dstInfo.colorSpace(),
                               premulState);
    }

    SkAlphaType dat = dstInfo.alphaType();
    if (SkTransferFunctionBehavior::kRespect == behavior) {
        if (kPremul_SkAlphaType == premulState && kUnpremul_SkAlphaType == dat) {
            pipeline.append(SkRasterPipeline::unpremul);
            premulState = kUnpremul_SkAlphaType;
        } else if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat) {
            pipeline.append(SkRasterPipeline::premul);
            premulState = kPremul_SkAlphaType;
        }
    }

    SkColorSpaceTransferFn dstFn;
    if (isColorAware && dstInfo.gammaCloseToSRGB()) {
        pipeline.append(SkRasterPipeline::to_srgb);
    } else if (isColorAware && !dstInfo.colorSpace()->gammaIsLinear()) {
        SkAssertResult(dstInfo.colorSpace()->isNumericalTransferFn(&dstFn));
        dstFn = dstFn.invert();
        pipeline.append(SkRasterPipeline::parametric_r, &dstFn);
        pipeline.append(SkRasterPipeline::parametric_g, &dstFn);
        pipeline.append(SkRasterPipeline::parametric_b, &dstFn);
    }

    if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat &&
        SkTransferFunctionBehavior::kIgnore == behavior)
    {
        pipeline.append(SkRasterPipeline::premul);
        premulState = kPremul_SkAlphaType;
    }

    // The final premul state must equal the dst alpha type.  Note that if we are "converting"
    // opaque to another alpha type, there's no need to worry about multiplication.
    SkASSERT(premulState == dat || kOpaque_SkAlphaType == srcInfo.alphaType());

    // We'll dither if we're decreasing precision below 32-bit.
    float dither_rate = 0.0f;
    if (srcInfo.bytesPerPixel() > dstInfo.bytesPerPixel()) {
        switch (dstInfo.colorType()) {
            case   kRGB_565_SkColorType: dither_rate = 1/63.0f; break;
            case kARGB_4444_SkColorType: dither_rate = 1/15.0f; break;
            default:                     dither_rate =    0.0f; break;
        }
    }
    if (dither_rate > 0) {
        pipeline.append(SkRasterPipeline::dither, &dither_rate);
    }

    switch (dstInfo.colorType()) {
        case kRGBA_8888_SkColorType:
            pipeline.append(SkRasterPipeline::store_8888, &dst);
            break;
        case kBGRA_8888_SkColorType:
            pipeline.append(SkRasterPipeline::store_bgra, &dst);
            break;
        case kRGB_565_SkColorType:
            pipeline.append(SkRasterPipeline::store_565, &dst);
            break;
        case kRGBA_F16_SkColorType:
            pipeline.append(SkRasterPipeline::store_f16, &dst);
            break;
        case kARGB_4444_SkColorType:
            pipeline.append(SkRasterPipeline::store_4444, &dst);
            break;
        default:
            SkASSERT(false);
            break;
    }

    pipeline.run(0,0, srcInfo.width(), srcInfo.height());
}

void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
                     const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
                     SkColorTable* ctable, SkTransferFunctionBehavior behavior) {
    SkASSERT(dstInfo.dimensions() == srcInfo.dimensions());
    SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo));

    // Fast Path 1: The memcpy() case.
    if (can_memcpy(dstInfo, srcInfo)) {
        SkRectMemcpy(dstPixels, dstRB, srcPixels, srcRB, dstInfo.minRowBytes(), dstInfo.height());
        return;
    }

    const bool isColorAware = dstInfo.colorSpace();
    SkASSERT(srcInfo.colorSpace() || !isColorAware);

    // Fast Path 2: Simple swizzles and premuls.
    if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel() && !isColorAware) {
        swizzle_and_multiply(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB);
        return;
    }

    // Fast Path 3: Alpha 8 dsts.
    if (kAlpha_8_SkColorType == dstInfo.colorType()) {
        convert_to_alpha8((uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
        return;
    }

    // Default: Use the pipeline.
    convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware,
                          behavior);
}
<commit_msg>Revert "remove another SkConvertPixels "fast path""<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkColorSpaceXform_Base.h"
#include "SkColorSpaceXformPriv.h"
#include "SkColorTable.h"
#include "SkConvertPixels.h"
#include "SkHalf.h"
#include "SkImageInfoPriv.h"
#include "SkOpts.h"
#include "SkPM4fPriv.h"
#include "SkRasterPipeline.h"
#include "SkUnPreMultiply.h"
#include "SkUnPreMultiplyPriv.h"
#include "../jumper/SkJumper.h"

// Fast Path 1: The memcpy() case.
static inline bool can_memcpy(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
    if (dstInfo.colorType() != srcInfo.colorType()) {
        return false;
    }

    if (kAlpha_8_SkColorType == dstInfo.colorType()) {
        return true;
    }

    if (dstInfo.alphaType() != srcInfo.alphaType() &&
        kOpaque_SkAlphaType != dstInfo.alphaType() &&
        kOpaque_SkAlphaType != srcInfo.alphaType())
    {
        // We need to premultiply or unpremultiply.
        return false;
    }

    return !dstInfo.colorSpace() ||
           SkColorSpace::Equals(dstInfo.colorSpace(), srcInfo.colorSpace());
}

// Fast Path 2: Simple swizzles and premuls.
enum AlphaVerb {
    kNothing_AlphaVerb,
    kPremul_AlphaVerb,
    kUnpremul_AlphaVerb,
};

template <bool kSwapRB>
static void wrap_unpremultiply(uint32_t* dst, const void* src, int count) {
    SkUnpremultiplyRow<kSwapRB>(dst, (const uint32_t*) src, count);
}

void swizzle_and_multiply(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
                          const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) {
    void (*proc)(uint32_t* dst, const void* src, int count);
    const bool swapRB = dstInfo.colorType() != srcInfo.colorType();
    AlphaVerb alphaVerb = kNothing_AlphaVerb;
    if (kPremul_SkAlphaType == dstInfo.alphaType() &&
        kUnpremul_SkAlphaType == srcInfo.alphaType())
    {
        alphaVerb = kPremul_AlphaVerb;
    } else if (kUnpremul_SkAlphaType == dstInfo.alphaType() &&
               kPremul_SkAlphaType == srcInfo.alphaType()) {
        alphaVerb = kUnpremul_AlphaVerb;
    }

    switch (alphaVerb) {
        case kNothing_AlphaVerb:
            // If we do not need to swap or multiply, we should hit the memcpy case.
            SkASSERT(swapRB);
            proc = SkOpts::RGBA_to_BGRA;
            break;
        case kPremul_AlphaVerb:
            proc = swapRB ? SkOpts::RGBA_to_bgrA : SkOpts::RGBA_to_rgbA;
            break;
        case kUnpremul_AlphaVerb:
            proc = swapRB ? wrap_unpremultiply<true> : wrap_unpremultiply<false>;
            break;
    }

    for (int y = 0; y < dstInfo.height(); y++) {
        proc((uint32_t*) dstPixels, srcPixels, dstInfo.width());
        dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
        srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
    }
}

// Fast Path 3: Color space xform.
static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo,
                                         SkTransferFunctionBehavior behavior) {
    // Unpremultiplication is unsupported by SkColorSpaceXform.  Note that if |src| is non-linearly
    // premultiplied, we're always going to have to unpremultiply before doing anything.
    if (kPremul_SkAlphaType == srcInfo.alphaType() &&
            (kUnpremul_SkAlphaType == dstInfo.alphaType() ||
             SkTransferFunctionBehavior::kIgnore == behavior)) {
        return false;
    }

    switch (dstInfo.colorType()) {
        case kRGBA_8888_SkColorType:
        case kBGRA_8888_SkColorType:
        case kRGBA_F16_SkColorType:
            break;
        default:
            return false;
    }

    switch (srcInfo.colorType()) {
        case kRGBA_8888_SkColorType:
        case kBGRA_8888_SkColorType:
            break;
        default:
            return false;
    }

    return true;
}

static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
                                     const SkImageInfo& srcInfo, const void* srcPixels,
                                     size_t srcRB, SkTransferFunctionBehavior behavior) {
    SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType());
    SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(srcInfo.colorType());
    SkAlphaType xformAlpha;
    switch (srcInfo.alphaType()) {
        case kOpaque_SkAlphaType:
            xformAlpha = kOpaque_SkAlphaType;
            break;
        case kPremul_SkAlphaType:
            SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType());

            // This signal means: copy the src alpha to the dst, do not premultiply (in this
            // case because the pixels are already premultiplied).
            xformAlpha = kUnpremul_SkAlphaType;
            break;
        case kUnpremul_SkAlphaType:
            SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType() ||
                     kUnpremul_SkAlphaType == dstInfo.alphaType());

            xformAlpha = dstInfo.alphaType();
            break;
        default:
            SkASSERT(false);
            xformAlpha = kUnpremul_SkAlphaType;
            break;
    }

    std::unique_ptr<SkColorSpaceXform> xform =
            SkColorSpaceXform_Base::New(srcInfo.colorSpace(), dstInfo.colorSpace(), behavior);
    SkASSERT(xform);

    for (int y = 0; y < dstInfo.height(); y++) {
        SkAssertResult(xform->apply(dstFormat, dstPixels, srcFormat, srcPixels, dstInfo.width(),
                       xformAlpha));
        dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
        srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
    }
}

// Fast Path 4: Alpha 8 dsts.
static void convert_to_alpha8(uint8_t* dst, size_t dstRB, const SkImageInfo& srcInfo,
                              const void* src, size_t srcRB, SkColorTable* ctable) {
    if (srcInfo.isOpaque()) {
        for (int y = 0; y < srcInfo.height(); ++y) {
           memset(dst, 0xFF, srcInfo.width());
           dst = SkTAddOffset<uint8_t>(dst, dstRB);
        }
        return;
    }

    switch (srcInfo.colorType()) {
        case kBGRA_8888_SkColorType:
        case kRGBA_8888_SkColorType: {
            auto src32 = (const uint32_t*) src;
            for (int y = 0; y < srcInfo.height(); y++) {
                for (int x = 0; x < srcInfo.width(); x++) {
                    dst[x] = src32[x] >> 24;
                }
                dst = SkTAddOffset<uint8_t>(dst, dstRB);
                src32 = SkTAddOffset<const uint32_t>(src32, srcRB);
            }
            break;
        }
        case kARGB_4444_SkColorType: {
            auto src16 = (const uint16_t*) src;
            for (int y = 0; y < srcInfo.height(); y++) {
                for (int x = 0; x < srcInfo.width(); x++) {
                    dst[x] = SkPacked4444ToA32(src16[x]);
                }
                dst = SkTAddOffset<uint8_t>(dst, dstRB);
                src16 = SkTAddOffset<const uint16_t>(src16, srcRB);
            }
            break;
        }
        case kRGBA_F16_SkColorType: {
            auto src64 = (const uint64_t*) src;
            for (int y = 0; y < srcInfo.height(); y++) {
                for (int x = 0; x < srcInfo.width(); x++) {
                    dst[x] = (uint8_t) (255.0f * SkHalfToFloat(src64[x] >> 48));
                }
                dst = SkTAddOffset<uint8_t>(dst, dstRB);
                src64 = SkTAddOffset<const uint64_t>(src64, srcRB);
            }
            break;
        }
        default:
            SkASSERT(false);
            break;
    }
}

// Default: Use the pipeline.
static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB,
                                  const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB,
                                  bool isColorAware, SkTransferFunctionBehavior behavior) {

    SkJumper_MemoryCtx src = { (void*)srcRow, (int)(srcRB / srcInfo.bytesPerPixel()) },
                       dst = { (void*)dstRow, (int)(dstRB / dstInfo.bytesPerPixel()) };

    SkRasterPipeline_<256> pipeline;
    switch (srcInfo.colorType()) {
        case kRGBA_8888_SkColorType:
            pipeline.append(SkRasterPipeline::load_8888, &src);
            break;
        case kBGRA_8888_SkColorType:
            pipeline.append(SkRasterPipeline::load_bgra, &src);
            break;
        case kRGB_565_SkColorType:
            pipeline.append(SkRasterPipeline::load_565, &src);
            break;
        case kRGBA_F16_SkColorType:
            pipeline.append(SkRasterPipeline::load_f16, &src);
            break;
        case kGray_8_SkColorType:
            pipeline.append(SkRasterPipeline::load_g8, &src);
            break;
        case kARGB_4444_SkColorType:
            pipeline.append(SkRasterPipeline::load_4444, &src);
            break;
        default:
            SkASSERT(false);
            break;
    }

    SkAlphaType premulState = srcInfo.alphaType();
    if (kPremul_SkAlphaType == premulState && SkTransferFunctionBehavior::kIgnore == behavior) {
        pipeline.append(SkRasterPipeline::unpremul);
        premulState = kUnpremul_SkAlphaType;
    }

    SkColorSpaceTransferFn srcFn;
    if (isColorAware && srcInfo.gammaCloseToSRGB()) {
        pipeline.append_from_srgb(premulState);
    } else if (isColorAware && !srcInfo.colorSpace()->gammaIsLinear()) {
        SkAssertResult(srcInfo.colorSpace()->isNumericalTransferFn(&srcFn));
        pipeline.append(SkRasterPipeline::parametric_r, &srcFn);
        pipeline.append(SkRasterPipeline::parametric_g, &srcFn);
        pipeline.append(SkRasterPipeline::parametric_b, &srcFn);
    }

    float matrix[12];
    if (isColorAware) {
        append_gamut_transform(&pipeline, matrix, srcInfo.colorSpace(), dstInfo.colorSpace(),
                               premulState);
    }

    SkAlphaType dat = dstInfo.alphaType();
    if (SkTransferFunctionBehavior::kRespect == behavior) {
        if (kPremul_SkAlphaType == premulState && kUnpremul_SkAlphaType == dat) {
            pipeline.append(SkRasterPipeline::unpremul);
            premulState = kUnpremul_SkAlphaType;
        } else if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat) {
            pipeline.append(SkRasterPipeline::premul);
            premulState = kPremul_SkAlphaType;
        }
    }

    SkColorSpaceTransferFn dstFn;
    if (isColorAware && dstInfo.gammaCloseToSRGB()) {
        pipeline.append(SkRasterPipeline::to_srgb);
    } else if (isColorAware && !dstInfo.colorSpace()->gammaIsLinear()) {
        SkAssertResult(dstInfo.colorSpace()->isNumericalTransferFn(&dstFn));
        dstFn = dstFn.invert();
        pipeline.append(SkRasterPipeline::parametric_r, &dstFn);
        pipeline.append(SkRasterPipeline::parametric_g, &dstFn);
        pipeline.append(SkRasterPipeline::parametric_b, &dstFn);
    }

    if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat &&
        SkTransferFunctionBehavior::kIgnore == behavior)
    {
        pipeline.append(SkRasterPipeline::premul);
        premulState = kPremul_SkAlphaType;
    }

    // The final premul state must equal the dst alpha type.  Note that if we are "converting"
    // opaque to another alpha type, there's no need to worry about multiplication.
    SkASSERT(premulState == dat || kOpaque_SkAlphaType == srcInfo.alphaType());

    // We'll dither if we're decreasing precision below 32-bit.
    float dither_rate = 0.0f;
    if (srcInfo.bytesPerPixel() > dstInfo.bytesPerPixel()) {
        switch (dstInfo.colorType()) {
            case   kRGB_565_SkColorType: dither_rate = 1/63.0f; break;
            case kARGB_4444_SkColorType: dither_rate = 1/15.0f; break;
            default:                     dither_rate =    0.0f; break;
        }
    }
    if (dither_rate > 0) {
        pipeline.append(SkRasterPipeline::dither, &dither_rate);
    }

    switch (dstInfo.colorType()) {
        case kRGBA_8888_SkColorType:
            pipeline.append(SkRasterPipeline::store_8888, &dst);
            break;
        case kBGRA_8888_SkColorType:
            pipeline.append(SkRasterPipeline::store_bgra, &dst);
            break;
        case kRGB_565_SkColorType:
            pipeline.append(SkRasterPipeline::store_565, &dst);
            break;
        case kRGBA_F16_SkColorType:
            pipeline.append(SkRasterPipeline::store_f16, &dst);
            break;
        case kARGB_4444_SkColorType:
            pipeline.append(SkRasterPipeline::store_4444, &dst);
            break;
        default:
            SkASSERT(false);
            break;
    }

    pipeline.run(0,0, srcInfo.width(), srcInfo.height());
}

void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
                     const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
                     SkColorTable* ctable, SkTransferFunctionBehavior behavior) {
    SkASSERT(dstInfo.dimensions() == srcInfo.dimensions());
    SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo));

    // Fast Path 1: The memcpy() case.
    if (can_memcpy(dstInfo, srcInfo)) {
        SkRectMemcpy(dstPixels, dstRB, srcPixels, srcRB, dstInfo.minRowBytes(), dstInfo.height());
        return;
    }

    const bool isColorAware = dstInfo.colorSpace();
    SkASSERT(srcInfo.colorSpace() || !isColorAware);

    // Fast Path 2: Simple swizzles and premuls.
    if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel() && !isColorAware) {
        swizzle_and_multiply(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB);
        return;
    }

    // Fast Path 3: Color space xform.
    if (isColorAware && optimized_color_xform(dstInfo, srcInfo, behavior)) {
        apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, behavior);
        return;
    }

    // Fast Path 4: Alpha 8 dsts.
    if (kAlpha_8_SkColorType == dstInfo.colorType()) {
        convert_to_alpha8((uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
        return;
    }

    // Default: Use the pipeline.
    convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware,
                          behavior);
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stx/util/binarymessagereader.h>
#include <cstable/CSTableReader.h>
#include <cstable/BooleanColumnReader.h>
#include <cstable/BitPackedIntColumnReader.h>
#include <cstable/UInt32ColumnReader.h>
#include <cstable/UInt64ColumnReader.h>
#include <cstable/LEB128ColumnReader.h>
#include <cstable/DoubleColumnReader.h>
#include <cstable/StringColumnReader.h>

namespace stx {
namespace cstable {

CSTableReader::CSTableReader(
    const String& filename) :
    CSTableReader(
        new io::MmappedFile(File::openFile(filename, File::O_READ))) {}

CSTableReader::CSTableReader(const RefPtr<VFSFile> file) : file_(file) {
  util::BinaryMessageReader header(file_->data(), file_->size());
  auto magic = *header.readUInt32();
  if (magic != BinaryFormat::kMagicBytes) {
    RAISE(kIllegalStateError, "not a valid cstable");
  }

  auto version = *header.readUInt16();
  if (version != BinaryFormat::kVersion) {
    RAISEF(kIllegalStateError, "unsupported sstable version: $0", version);
  }

  auto flags = *header.readUInt64();
  num_records_ = *header.readUInt64();
  num_columns_ = *header.readUInt32();

  for (int i = 0; i < num_columns_; ++i) {
    auto type = *header.readUInt32();
    auto name_len = *header.readUInt32();
    auto name_data = (char *) header.read(name_len);

    auto r_max = *header.readUInt32();
    auto d_max = *header.readUInt32();
    auto body_offset = *header.readUInt64();
    auto size = *header.readUInt64();

    ColumnInfo ci;
    ci.type = (ColumnType) type;
    ci.name = String(name_data, name_len);
    ci.body_offset = body_offset;
    ci.size = size;
    ci.r_max = r_max;
    ci.d_max = d_max;
    columns_.emplace(ci.name, ci);
  }
}

RefPtr<ColumnReader> CSTableReader::getColumnReader(const String& column_name) {
  auto col = columns_.find(column_name);
  if (col == columns_.end()) {
    RAISEF(kIndexError, "unknown column: $0", column_name);
  }

  const auto& c = col->second;
  void* cdata = ((char *) file_->data()) + col->second.body_offset;

  switch (c.type) {
    case ColumnType::BOOLEAN:
      return new BooleanColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::UINT32_BITPACKED:
      return new BitPackedIntColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::UINT32_PLAIN:
      return new UInt32ColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::UINT64_PLAIN:
      return new UInt64ColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::UINT64_LEB128:
      return new LEB128ColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::DOUBLE:
      return new DoubleColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::STRING_PLAIN:
      return new StringColumnReader(c.r_max, c.d_max, cdata, c.size);
  }

  RAISEF(kIllegalStateError, "invalid column type: $0", (uint32_t) c.type);
}

bool CSTableReader::hasColumn(const String& column_name) const {
  auto col = columns_.find(column_name);
  return col != columns_.end();
}

void CSTableReader::getColumn(
    const String& column_name,
    void** data,
    size_t* size) {
  auto col = columns_.find(column_name);
  if (col == columns_.end()) {
    RAISEF(kIndexError, "unknown column: $0", column_name);
  }

  *data = ((char *) file_->data()) + col->second.body_offset;
  *size = col->second.size;
}

size_t CSTableReader::numRecords() const {
  return num_records_;
}

} // namespace cstable
} // namespace stx

<commit_msg>fix warning<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stx/util/binarymessagereader.h>
#include <cstable/CSTableReader.h>
#include <cstable/BooleanColumnReader.h>
#include <cstable/BitPackedIntColumnReader.h>
#include <cstable/UInt32ColumnReader.h>
#include <cstable/UInt64ColumnReader.h>
#include <cstable/LEB128ColumnReader.h>
#include <cstable/DoubleColumnReader.h>
#include <cstable/StringColumnReader.h>

namespace stx {
namespace cstable {

CSTableReader::CSTableReader(
    const String& filename) :
    CSTableReader(
        new io::MmappedFile(File::openFile(filename, File::O_READ))) {}

CSTableReader::CSTableReader(const RefPtr<VFSFile> file) : file_(file) {
  util::BinaryMessageReader header(file_->data(), file_->size());
  auto magic = *header.readUInt32();
  if (magic != BinaryFormat::kMagicBytes) {
    RAISE(kIllegalStateError, "not a valid cstable");
  }

  auto version = *header.readUInt16();
  if (version != BinaryFormat::kVersion) {
    RAISEF(kIllegalStateError, "unsupported sstable version: $0", version);
  }

  auto flags = *header.readUInt64();
  num_records_ = *header.readUInt64();
  num_columns_ = *header.readUInt32();

  (void) flags; // make gcc happy

  for (int i = 0; i < num_columns_; ++i) {
    auto type = *header.readUInt32();
    auto name_len = *header.readUInt32();
    auto name_data = (char *) header.read(name_len);

    auto r_max = *header.readUInt32();
    auto d_max = *header.readUInt32();
    auto body_offset = *header.readUInt64();
    auto size = *header.readUInt64();

    ColumnInfo ci;
    ci.type = (ColumnType) type;
    ci.name = String(name_data, name_len);
    ci.body_offset = body_offset;
    ci.size = size;
    ci.r_max = r_max;
    ci.d_max = d_max;
    columns_.emplace(ci.name, ci);
  }
}

RefPtr<ColumnReader> CSTableReader::getColumnReader(const String& column_name) {
  auto col = columns_.find(column_name);
  if (col == columns_.end()) {
    RAISEF(kIndexError, "unknown column: $0", column_name);
  }

  const auto& c = col->second;
  void* cdata = ((char *) file_->data()) + col->second.body_offset;

  switch (c.type) {
    case ColumnType::BOOLEAN:
      return new BooleanColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::UINT32_BITPACKED:
      return new BitPackedIntColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::UINT32_PLAIN:
      return new UInt32ColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::UINT64_PLAIN:
      return new UInt64ColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::UINT64_LEB128:
      return new LEB128ColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::DOUBLE:
      return new DoubleColumnReader(c.r_max, c.d_max, cdata, c.size);
    case ColumnType::STRING_PLAIN:
      return new StringColumnReader(c.r_max, c.d_max, cdata, c.size);
  }

  RAISEF(kIllegalStateError, "invalid column type: $0", (uint32_t) c.type);
}

bool CSTableReader::hasColumn(const String& column_name) const {
  auto col = columns_.find(column_name);
  return col != columns_.end();
}

void CSTableReader::getColumn(
    const String& column_name,
    void** data,
    size_t* size) {
  auto col = columns_.find(column_name);
  if (col == columns_.end()) {
    RAISEF(kIndexError, "unknown column: $0", column_name);
  }

  *data = ((char *) file_->data()) + col->second.body_offset;
  *size = col->second.size;
}

size_t CSTableReader::numRecords() const {
  return num_records_;
}

} // namespace cstable
} // namespace stx

<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.10  2000/07/17 23:00:16  jpolast
 * bug fix for SHOW_ELEMENT flag incorrectly being retreived.
 * contributed by Grace Yan and Joe Kesselman.
 *
 * Revision 1.9  2000/03/02 19:54:03  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.8  2000/02/08 20:26:11  aruna1
 * NodeIterator problem solved
 *
 * Revision 1.7  2000/02/08 01:16:18  aruna1
 * nodeIterator previous tracking problem solved
 *
 * Revision 1.6  2000/02/06 07:47:33  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.5  2000/02/04 01:49:26  aruna1
 * TreeWalker and NodeIterator changes
 *
 * Revision 1.4  1999/11/30 21:16:25  roddey
 * Changes to add the transcode() method to DOMString, which returns a transcoded
 * version (to local code page) of the DOM string contents. And I changed all of the
 * exception 'throw by pointer' to 'throw by value' style.
 *
 * Revision 1.3  1999/11/23 01:48:16  rahulj
 * Changed 0L to 0. CC under HPUX is happy now.
 *
 * Revision 1.2  1999/11/20 00:56:39  rahulj
 * Source files must end with an un-escaped newline.
 *
 * Revision 1.1.1.1  1999/11/09 01:09:15  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:44:30  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// NodeIteratorImpl.cpp: implementation of the NodeIteratorImpl class.
//
//////////////////////////////////////////////////////////////////////

#include "NodeIteratorImpl.hpp"
#include "DOM_Document.hpp"
#include "DOM_DOMException.hpp"
#include "DocumentImpl.hpp"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

NodeIteratorImpl::NodeIteratorImpl ()
: fDetached(false),
    fNodeFilter(0)
{
}

NodeIteratorImpl::~NodeIteratorImpl ()
{
	fDetached = false;
}

void NodeIteratorImpl::detach ()
{
	fDetached = true;
}

NodeIteratorImpl::NodeIteratorImpl (
                                    DOM_Node root,
                                    unsigned long whatToShow,
                                    DOM_NodeFilter* nodeFilter,
                                    bool expandEntityRef)
:   fDetached(false),
    fRoot(root),
    fCurrentNode(0),
    fWhatToShow(whatToShow),
    fNodeFilter(nodeFilter),
    fForward(true),
    fExpandEntityReferences(expandEntityRef)
{

}

NodeIteratorImpl::NodeIteratorImpl ( const NodeIteratorImpl& toCopy)
    :   fDetached(toCopy.fDetached),
    fRoot(toCopy.fRoot),
    fCurrentNode(toCopy.fCurrentNode),
    fWhatToShow(toCopy.fWhatToShow),
    fNodeFilter(toCopy.fNodeFilter),
    fForward(toCopy.fForward),
    fExpandEntityReferences(toCopy.fExpandEntityReferences)
{
}

NodeIteratorImpl& NodeIteratorImpl::operator= (const NodeIteratorImpl& other) {
    fRoot                   = other.fRoot;
    fCurrentNode            = other.fRoot;
    fWhatToShow             = other.fWhatToShow;
    fNodeFilter             = other.fNodeFilter;
    fForward                = other.fForward;
	fDetached               = other.fDetached;
    fExpandEntityReferences = other.fExpandEntityReferences;
    return *this;
}

// Implementation Note: Note that the iterator looks at whatToShow
// and filter values at each call, and therefore one _could_ add
// setters for these values and alter them while iterating!

/** Return the whatToShow value */

unsigned long NodeIteratorImpl::getWhatToShow () {
    return fWhatToShow;
}

/** Return the filter */

DOM_NodeFilter* NodeIteratorImpl::getFilter () {
    return fNodeFilter;
}

/** Get the expandEntity reference flag. */
bool NodeIteratorImpl::getExpandEntityReferences()
{
    return fExpandEntityReferences;
}

/** Return the next DOM_Node in the Iterator. The node is the next node in
 *  depth-first order which also passes the filter, and whatToShow.
 *  A null return means either that
 */

DOM_Node NodeIteratorImpl::nextNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if root is null there is no next node.
    if (fRoot.isNull())
			return result;

    DOM_Node aNextNode = fCurrentNode;
    bool accepted = false; // the next node has not been accepted.

    while (!accepted) {

        // if last direction is not forward, repeat node.
        if (!fForward && !aNextNode.isNull()) {
            //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
            aNextNode = fCurrentNode;
        } else {
        // else get the next node via depth-first
            aNextNode = nextNode(aNextNode, true);
        }

        fForward = true; //REVIST: should direction be set forward before null check?

        // nothing in the list. return null.
        if (aNextNode.isNull())
					return result;

        // does node pass the filters and whatToShow?
        accepted = acceptNode(aNextNode);
        if (accepted) {
            // if so, then the node is the current node.
            fCurrentNode = aNextNode;
            return fCurrentNode;
				}

    }

    // no nodes, or no accepted nodes.
    return result;
}

/** Return the previous Node in the Iterator. The node is the next node in
 *  _backwards_ depth-first order which also passes the filter, and whatToShow.
 */

DOM_Node NodeIteratorImpl::previousNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if the root is null, or the current node is null, return null.
    if (fRoot.isNull() || fCurrentNode.isNull())
			return result;

    DOM_Node aPreviousNode = fCurrentNode;
    bool accepted = false;

    while (!accepted) {

        if (fForward && ! aPreviousNode.isNull()) {
            //repeat last node.
            aPreviousNode = fCurrentNode;
        } else {
            // get previous node in backwards depth first order.
            aPreviousNode = previousNode(aPreviousNode);
        }

        // we are going backwards
        fForward = false;

        // if the new previous node is null, we're at head or past the root,
        // so return null.
        if (aPreviousNode.isNull())
					return result;

        // check if node passes filters and whatToShow.
        accepted = acceptNode(aPreviousNode);
        if (accepted) {
            // if accepted, update the current node, and return it.
            fCurrentNode = aPreviousNode;
            return fCurrentNode;
        }
    }
    // there are no nodes?
    return result;
}

/** The node is accepted if it passes the whatToShow and the filter. */
bool NodeIteratorImpl::acceptNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (fNodeFilter == 0) {
        return ((fWhatToShow & (1 << (node.getNodeType() - 1))) != 0);
    } else {
        return ((fWhatToShow & (1 << (node.getNodeType() - 1))) != 0)
            && fNodeFilter->acceptNode(node) == DOM_NodeFilter::FILTER_ACCEPT;
    }
}

/** Return node, if matches or any parent if matches. */
DOM_Node NodeIteratorImpl::matchNodeOrParent (DOM_Node node) {
		DOM_Node result;

    for (DOM_Node n = node; n != fRoot; n = n.getParentNode()) {
        if (node == n) return n;
    }

    return result;
}

/** The method nextNode(DOM_Node, bool) returns the next node
 *  from the actual DOM tree.
 *
 *  The bool visitChildren determines whether to visit the children.
 *  The result is the nextNode.
 */

DOM_Node NodeIteratorImpl::nextNode (DOM_Node node, bool visitChildren) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (node.isNull()) return fRoot;

    DOM_Node result;
    // only check children if we visit children.
    if (visitChildren) {
        //if hasChildren, return 1st child.
        if (node.hasChildNodes()) {
            result = node.getFirstChild();
            return result;
        }
    }

    // if hasSibling, return sibling
    result = node.getNextSibling();
    if (! result.isNull()) return result;

    // return parent's 1st sibling.
    DOM_Node parent = node.getParentNode();
    while (!parent.isNull() && parent != fRoot) {
        result = parent.getNextSibling();
        if (!result.isNull()) {
            return result;
        } else {
            parent = parent.getParentNode();
        }

    } // while (parent != null && parent != fRoot) {

    // end of list, return null
		DOM_Node aNull;
    return aNull;
}

/** The method previousNode(DOM_Node) returns the previous node
 *  from the actual DOM tree.
 */

DOM_Node NodeIteratorImpl::previousNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    DOM_Node result;

    // if we're at the root, return null.
    if (node == fRoot)
			return result;

    // get sibling
    result = node.getPreviousSibling();
    if (result.isNull()) {
        //if 1st sibling, return parent
        result = node.getParentNode();
        return result;
    }

    // if sibling has children, keep getting last child of child.
    if (result.hasChildNodes()) {
        while (result.hasChildNodes()) {
            result = result.getLastChild();
        }
    }

    return result;
}

/** Fix-up the iterator on a remove. Called by DOM or otherwise,
 *  before an actual DOM remove.
 */

void NodeIteratorImpl::removeNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    // Implementation note: Fix-up means setting the current node properly
    // after a remove.

    if (node.isNull())
				return;

    DOM_Node deleted = matchNodeOrParent(node);

    if (deleted.isNull()) return;

    if (fForward) {
        fCurrentNode = previousNode(deleted);
    } else
    // if (!fForward)
    {
        DOM_Node next = nextNode(deleted, false);
        if (! next.isNull()) {
            // normal case: there _are_ nodes following this in the iterator.
            fCurrentNode = next;
        } else {
            // the last node in the iterator is to be removed,
            // so we set the current node to be the previous one.
            fCurrentNode = previousNode(deleted);
            fForward = true;
        }

    }

}

void NodeIteratorImpl::unreferenced()
{
    DOM_Document doc = fRoot.getOwnerDocument();
    DocumentImpl* impl;

    if (! doc.isNull()) {
        impl = (DocumentImpl *) doc.fImpl;
    }
    else
        impl = (DocumentImpl *) fRoot.fImpl;

    if (impl->iterators != 0L) {
        int i;
        int sz = impl->iterators->size();
        for (i = 0; i < sz; i++)
            if (impl->iterators->elementAt(i) == this) {
                impl->iterators->removeElementAt(i);
                break;
            }
    }

    delete this;
}
<commit_msg>DOM NodeIterator bug fix - iterators would sometimes continue beyond their starting (root) node.  Fix from Tinny Ng.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.11  2000/11/01 01:26:30  andyh
 * DOM NodeIterator bug fix - iterators would sometimes continue beyond
 * their starting (root) node.  Fix from Tinny Ng.
 *
 * Revision 1.10  2000/07/17 23:00:16  jpolast
 * bug fix for SHOW_ELEMENT flag incorrectly being retreived.
 * contributed by Grace Yan and Joe Kesselman.
 *
 * Revision 1.9  2000/03/02 19:54:03  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.8  2000/02/08 20:26:11  aruna1
 * NodeIterator problem solved
 *
 * Revision 1.7  2000/02/08 01:16:18  aruna1
 * nodeIterator previous tracking problem solved
 *
 * Revision 1.6  2000/02/06 07:47:33  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.5  2000/02/04 01:49:26  aruna1
 * TreeWalker and NodeIterator changes
 *
 * Revision 1.4  1999/11/30 21:16:25  roddey
 * Changes to add the transcode() method to DOMString, which returns a transcoded
 * version (to local code page) of the DOM string contents. And I changed all of the
 * exception 'throw by pointer' to 'throw by value' style.
 *
 * Revision 1.3  1999/11/23 01:48:16  rahulj
 * Changed 0L to 0. CC under HPUX is happy now.
 *
 * Revision 1.2  1999/11/20 00:56:39  rahulj
 * Source files must end with an un-escaped newline.
 *
 * Revision 1.1.1.1  1999/11/09 01:09:15  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:44:30  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// NodeIteratorImpl.cpp: implementation of the NodeIteratorImpl class.
//
//////////////////////////////////////////////////////////////////////

#include "NodeIteratorImpl.hpp"
#include "DOM_Document.hpp"
#include "DOM_DOMException.hpp"
#include "DocumentImpl.hpp"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

NodeIteratorImpl::NodeIteratorImpl ()
: fDetached(false),
    fNodeFilter(0)
{
}

NodeIteratorImpl::~NodeIteratorImpl ()
{
	fDetached = false;
}

void NodeIteratorImpl::detach ()
{
	fDetached = true;
}

NodeIteratorImpl::NodeIteratorImpl (
                                    DOM_Node root,
                                    unsigned long whatToShow,
                                    DOM_NodeFilter* nodeFilter,
                                    bool expandEntityRef)
:   fDetached(false),
    fRoot(root),
    fCurrentNode(0),
    fWhatToShow(whatToShow),
    fNodeFilter(nodeFilter),
    fForward(true),
    fExpandEntityReferences(expandEntityRef)
{

}

NodeIteratorImpl::NodeIteratorImpl ( const NodeIteratorImpl& toCopy)
    :   fDetached(toCopy.fDetached),
    fRoot(toCopy.fRoot),
    fCurrentNode(toCopy.fCurrentNode),
    fWhatToShow(toCopy.fWhatToShow),
    fNodeFilter(toCopy.fNodeFilter),
    fForward(toCopy.fForward),
    fExpandEntityReferences(toCopy.fExpandEntityReferences)
{
}

NodeIteratorImpl& NodeIteratorImpl::operator= (const NodeIteratorImpl& other) {
    fRoot                   = other.fRoot;
    fCurrentNode            = other.fRoot;
    fWhatToShow             = other.fWhatToShow;
    fNodeFilter             = other.fNodeFilter;
    fForward                = other.fForward;
	fDetached               = other.fDetached;
    fExpandEntityReferences = other.fExpandEntityReferences;
    return *this;
}

// Implementation Note: Note that the iterator looks at whatToShow
// and filter values at each call, and therefore one _could_ add
// setters for these values and alter them while iterating!

/** Return the whatToShow value */

unsigned long NodeIteratorImpl::getWhatToShow () {
    return fWhatToShow;
}

/** Return the filter */

DOM_NodeFilter* NodeIteratorImpl::getFilter () {
    return fNodeFilter;
}

/** Get the expandEntity reference flag. */
bool NodeIteratorImpl::getExpandEntityReferences()
{
    return fExpandEntityReferences;
}

/** Return the next DOM_Node in the Iterator. The node is the next node in
 *  depth-first order which also passes the filter, and whatToShow.
 *  A null return means either that
 */

DOM_Node NodeIteratorImpl::nextNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if root is null there is no next node.
    if (fRoot.isNull())
			return result;

    DOM_Node aNextNode = fCurrentNode;
    bool accepted = false; // the next node has not been accepted.

    while (!accepted) {

        // if last direction is not forward, repeat node.
        if (!fForward && !aNextNode.isNull()) {
            //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
            aNextNode = fCurrentNode;
        } else {
        // else get the next node via depth-first
            aNextNode = nextNode(aNextNode, true);
        }

        fForward = true; //REVIST: should direction be set forward before null check?

        // nothing in the list. return null.
        if (aNextNode.isNull())
					return result;

        // does node pass the filters and whatToShow?
        accepted = acceptNode(aNextNode);
        if (accepted) {
            // if so, then the node is the current node.
            fCurrentNode = aNextNode;
            return fCurrentNode;
				}

    }

    // no nodes, or no accepted nodes.
    return result;
}

/** Return the previous Node in the Iterator. The node is the next node in
 *  _backwards_ depth-first order which also passes the filter, and whatToShow.
 */

DOM_Node NodeIteratorImpl::previousNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if the root is null, or the current node is null, return null.
    if (fRoot.isNull() || fCurrentNode.isNull())
			return result;

    DOM_Node aPreviousNode = fCurrentNode;
    bool accepted = false;

    while (!accepted) {

        if (fForward && ! aPreviousNode.isNull()) {
            //repeat last node.
            aPreviousNode = fCurrentNode;
        } else {
            // get previous node in backwards depth first order.
            aPreviousNode = previousNode(aPreviousNode);
        }

        // we are going backwards
        fForward = false;

        // if the new previous node is null, we're at head or past the root,
        // so return null.
        if (aPreviousNode.isNull())
					return result;

        // check if node passes filters and whatToShow.
        accepted = acceptNode(aPreviousNode);
        if (accepted) {
            // if accepted, update the current node, and return it.
            fCurrentNode = aPreviousNode;
            return fCurrentNode;
        }
    }
    // there are no nodes?
    return result;
}

/** The node is accepted if it passes the whatToShow and the filter. */
bool NodeIteratorImpl::acceptNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (fNodeFilter == 0) {
        return ((fWhatToShow & (1 << (node.getNodeType() - 1))) != 0);
    } else {
        return ((fWhatToShow & (1 << (node.getNodeType() - 1))) != 0)
            && fNodeFilter->acceptNode(node) == DOM_NodeFilter::FILTER_ACCEPT;
    }
}

/** Return node, if matches or any parent if matches. */
DOM_Node NodeIteratorImpl::matchNodeOrParent (DOM_Node node) {
		DOM_Node result;

    for (DOM_Node n = node; n != fRoot; n = n.getParentNode()) {
        if (node == n) return n;
    }

    return result;
}

/** The method nextNode(DOM_Node, bool) returns the next node
 *  from the actual DOM tree.
 *
 *  The bool visitChildren determines whether to visit the children.
 *  The result is the nextNode.
 */

DOM_Node NodeIteratorImpl::nextNode (DOM_Node node, bool visitChildren) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (node.isNull()) return fRoot;

    DOM_Node result;
    // only check children if we visit children.
    if (visitChildren) {
        //if hasChildren, return 1st child.
        if (node.hasChildNodes()) {
            result = node.getFirstChild();
            return result;
        }
    }

    // if hasSibling, return sibling
    if (node != fRoot) {
        result = node.getNextSibling();
        if (! result.isNull()) return result;

        // return parent's 1st sibling.
        DOM_Node parent = node.getParentNode();
        while (!parent.isNull() && parent != fRoot) {
            result = parent.getNextSibling();
            if (!result.isNull()) {
                return result;
            } else {
                parent = parent.getParentNode();
            }

        } // while (parent != null && parent != fRoot) {
    }
    // end of list, return null
    DOM_Node aNull;
    return aNull;
}

/** The method previousNode(DOM_Node) returns the previous node
 *  from the actual DOM tree.
 */

DOM_Node NodeIteratorImpl::previousNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    DOM_Node result;

    // if we're at the root, return null.
    if (node == fRoot)
			return result;

    // get sibling
    result = node.getPreviousSibling();
    if (result.isNull()) {
        //if 1st sibling, return parent
        result = node.getParentNode();
        return result;
    }

    // if sibling has children, keep getting last child of child.
    if (result.hasChildNodes()) {
        while (result.hasChildNodes()) {
            result = result.getLastChild();
        }
    }

    return result;
}

/** Fix-up the iterator on a remove. Called by DOM or otherwise,
 *  before an actual DOM remove.
 */

void NodeIteratorImpl::removeNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    // Implementation note: Fix-up means setting the current node properly
    // after a remove.

    if (node.isNull())
				return;

    DOM_Node deleted = matchNodeOrParent(node);

    if (deleted.isNull()) return;

    if (fForward) {
        fCurrentNode = previousNode(deleted);
    } else
    // if (!fForward)
    {
        DOM_Node next = nextNode(deleted, false);
        if (! next.isNull()) {
            // normal case: there _are_ nodes following this in the iterator.
            fCurrentNode = next;
        } else {
            // the last node in the iterator is to be removed,
            // so we set the current node to be the previous one.
            fCurrentNode = previousNode(deleted);
            fForward = true;
        }

    }

}

void NodeIteratorImpl::unreferenced()
{
    DOM_Document doc = fRoot.getOwnerDocument();
    DocumentImpl* impl;

    if (! doc.isNull()) {
        impl = (DocumentImpl *) doc.fImpl;
    }
    else
        impl = (DocumentImpl *) fRoot.fImpl;

    if (impl->iterators != 0L) {
        int i;
        int sz = impl->iterators->size();
        for (i = 0; i < sz; i++)
            if (impl->iterators->elementAt(i) == this) {
                impl->iterators->removeElementAt(i);
                break;
            }
    }

    delete this;
}
<|endoftext|>


<commit_before>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.

This file is part of the Daemon GPL Source Code (Daemon Source Code).

Daemon Source Code 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.

Daemon Source Code 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 Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

===========================================================================
*/

// sv_bot.c

#include "server.h"

/*
==================
SV_BotAllocateClient
==================
*/
int SV_BotAllocateClient( void )
{
	int      i;
	// Never use the first slot otherwise: if a bot connect before the first client game supposedly won't start
	int      firstSlot = std::max( 1, sv_privateClients->integer );
	client_t *cl;

	// find a free client slot which was occupied by a bot (doesn't matter which)
	for ( i = firstSlot, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
	{
		if ( cl->state == CS_FREE && cl->netchan.remoteAddress.type == NA_BOT )
		{
			break;
		}
	}

	// find any free client slot
	if ( i == sv_maxclients->integer )
	{
		for ( i = firstSlot, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
		{
			if ( cl->state == CS_FREE )
			{
				break;
			}
		}
	}

	if ( i >= sv_maxclients->integer )
	{
		return -1;
	}

	cl->gentity = SV_GentityNum( i );
	cl->gentity->s.number = i;
	cl->state = CS_ACTIVE;
	cl->lastPacketTime = svs.time;
	cl->netchan.remoteAddress.type = NA_BOT;
	cl->rate = 16384;

	return i;
}

/*
==================
SV_BotFreeClient
==================
*/
void SV_BotFreeClient( int clientNum )
{
	client_t *cl;

	if ( clientNum < 0 || clientNum >= sv_maxclients->integer )
	{
		Com_Error( ERR_DROP, "SV_BotFreeClient: bad clientNum: %i", clientNum );
	}

	cl = &svs.clients[ clientNum ];
	cl->state = CS_FREE;
	cl->name[ 0 ] = 0;
}

/*
==================
SV_IsBot
==================
*/
bool SV_IsBot( const client_t* client )
{
	return client->netchan.remoteAddress.type == NA_BOT && client->state == CS_ACTIVE;
}

//
//  * * * BOT AI CODE IS BELOW THIS POINT * * *
//

/*
==================
SV_BotGetConsoleMessage
==================
*/
int SV_BotGetConsoleMessage( int client, char *buf, int size )
{
	client_t *cl;
	int      index;

	cl = &svs.clients[ client ];
	cl->lastPacketTime = svs.time;

	if ( cl->reliableAcknowledge == cl->reliableSequence )
	{
		return qfalse;
	}

	cl->reliableAcknowledge++;
	index = cl->reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 );

	if ( !cl->reliableCommands[ index ][ 0 ] )
	{
		return qfalse;
	}

	//Q_strncpyz( buf, cl->reliableCommands[index], size );
	return qtrue;
}

<commit_msg>Fix clients connecting as bots (and related problems)<commit_after>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.

This file is part of the Daemon GPL Source Code (Daemon Source Code).

Daemon Source Code 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.

Daemon Source Code 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 Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

===========================================================================
*/

// sv_bot.c

#include "server.h"

/*
==================
SV_BotAllocateClient
==================
*/
int SV_BotAllocateClient( void )
{
	int      i;
	// Never use the first slot otherwise: if a bot connect before the first client game supposedly won't start
	int      firstSlot = std::max( 1, sv_privateClients->integer );
	client_t *cl;

	// find a free client slot which was occupied by a bot (doesn't matter which)
	for ( i = firstSlot, cl = svs.clients + firstSlot; i < sv_maxclients->integer; i++, cl++ )
	{
		if ( cl->state == CS_FREE && cl->netchan.remoteAddress.type == NA_BOT )
		{
			break;
		}
	}

	// find any free client slot
	if ( i == sv_maxclients->integer )
	{
		for ( i = firstSlot, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
		{
			if ( cl->state == CS_FREE )
			{
				break;
			}
		}
	}

	if ( i >= sv_maxclients->integer )
	{
		return -1;
	}

	cl->gentity = SV_GentityNum( i );
	cl->gentity->s.number = i;
	cl->state = CS_ACTIVE;
	cl->lastPacketTime = svs.time;
	cl->netchan.remoteAddress.type = NA_BOT;
	cl->rate = 16384;

	return i;
}

/*
==================
SV_BotFreeClient
==================
*/
void SV_BotFreeClient( int clientNum )
{
	client_t *cl;

	if ( clientNum < 0 || clientNum >= sv_maxclients->integer )
	{
		Com_Error( ERR_DROP, "SV_BotFreeClient: bad clientNum: %i", clientNum );
	}

	cl = &svs.clients[ clientNum ];
	cl->state = CS_FREE;
	cl->name[ 0 ] = 0;
}

/*
==================
SV_IsBot
==================
*/
bool SV_IsBot( const client_t* client )
{
	return client->netchan.remoteAddress.type == NA_BOT && client->state == CS_ACTIVE;
}

//
//  * * * BOT AI CODE IS BELOW THIS POINT * * *
//

/*
==================
SV_BotGetConsoleMessage
==================
*/
int SV_BotGetConsoleMessage( int client, char *buf, int size )
{
	client_t *cl;
	int      index;

	cl = &svs.clients[ client ];
	cl->lastPacketTime = svs.time;

	if ( cl->reliableAcknowledge == cl->reliableSequence )
	{
		return qfalse;
	}

	cl->reliableAcknowledge++;
	index = cl->reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 );

	if ( !cl->reliableCommands[ index ][ 0 ] )
	{
		return qfalse;
	}

	//Q_strncpyz( buf, cl->reliableCommands[index], size );
	return qtrue;
}

<|endoftext|>


<commit_before>#ifndef ENTT_RESOURCE_HANDLE_HPP
#define ENTT_RESOURCE_HANDLE_HPP

#include <memory>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "fwd.hpp"

namespace entt {

/**
 * @brief Shared resource handle.
 *
 * A shared resource handle is a small class that wraps a resource and keeps it
 * alive even if it's deleted from the cache. It can be either copied or
 * moved. A handle shares a reference to the same resource with all the other
 * handles constructed for the same identifier.

 * As a rule of thumb, resources should never be copied nor moved. Handles are
 * the way to go to keep references to them.
 *
 * @tparam Resource Type of resource managed by a handle.
 */
template<typename Resource>
class resource_handle {
    /*! @brief Resource handles are friends with each other. */
    template<typename>
    friend class resource_handle;

public:
    /*! @brief Value type. */
    using value_type = Resource;
    /*! @brief Reference type. */
    using reference = value_type &;
    /*! @brief Pointer type. */
    using pointer = value_type *;
    /*! @brief Unsigned integer type. */
    using size_type = long;

    /*! @brief Default constructor. */
    resource_handle() ENTT_NOEXCEPT = default;

    /**
     * @brief Creates a handle from a shared pointer, namely a resource.
     * @param res A pointer to a properly initialized resource.
     */
    resource_handle(std::shared_ptr<value_type> res) ENTT_NOEXCEPT
        : resource{std::move(res)} {}

    /**
     * @brief Copy constructor.
     * @param other The instance to copy from.
     */
    resource_handle(const resource_handle &other) ENTT_NOEXCEPT = default;

    /**
     * @brief Move constructor.
     * @param other The instance to move from.
     */
    resource_handle(resource_handle &&other) ENTT_NOEXCEPT = default;

    /**
     * @brief Aliasing constructor.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle with which to share ownership information.
     * @param res Unrelated and unmanaged resources.
     */
    template<typename Other>
    resource_handle(const resource_handle<Other> &other, value_type &res) ENTT_NOEXCEPT
        : resource{other.resource, std::addressof(res)} {}

    /**
     * @brief Copy constructs a handle which shares ownership of the resource.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to copy from.
     */
    template<typename Other, typename = std::enable_if_t<!std::is_same_v<value_type, Other> && std::is_base_of_v<value_type, Other>>>
    resource_handle(const resource_handle<Other> &other) ENTT_NOEXCEPT
        : resource{other.resource} {}

    /**
     * @brief Move constructs a handle which takes ownership of the resource.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to move from.
     */
    template<typename Other, typename = std::enable_if_t<!std::is_same_v<value_type, Other> && std::is_base_of_v<value_type, Other>>>
    resource_handle(resource_handle<Other> &&other) ENTT_NOEXCEPT
        : resource{std::move(other.resource)} {}

    /**
     * @brief Copy assignment operator.
     * @param other The instance to copy from.
     * @return This resource handle.
     */
    resource_handle &operator=(const resource_handle &other) ENTT_NOEXCEPT = default;

    /**
     * @brief Move assignment operator.
     * @param other The instance to move from.
     * @return This resource handle.
     */
    resource_handle &operator=(resource_handle &&other) ENTT_NOEXCEPT = default;

    /**
     * @brief Copy assignment operator from foreign handle.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to copy from.
     * @return This resource handle.
     */
    template<typename Other>
    std::enable_if_t<!std::is_same_v<value_type, Other> && std::is_base_of_v<value_type, Other>, resource_handle &>
    operator=(const resource_handle<Other> &other) ENTT_NOEXCEPT {
        resource = other.resource;
        return *this;
    }

    /**
     * @brief Move assignment operator from foreign handle.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to move from.
     * @return This resource handle.
     */
    template<typename Other>
    std::enable_if_t<!std::is_same_v<value_type, Other> && std::is_base_of_v<value_type, Other>, resource_handle &>
    operator=(resource_handle<Other> &&other) ENTT_NOEXCEPT {
        resource = std::move(other.resource);
        return *this;
    }

    /**
     * @brief Gets a reference to the managed resource.
     *
     * @warning
     * The behavior is undefined if the handle doesn't contain a resource.
     *
     * @return A reference to the managed resource.
     */
    [[nodiscard]] reference get() const ENTT_NOEXCEPT {
        return *resource;
    }

    /*! @copydoc get */
    [[nodiscard]] operator reference() const ENTT_NOEXCEPT {
        return get();
    }

    /*! @copydoc get */
    [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
        return get();
    }

    /**
     * @brief Gets a pointer to the managed resource.
     *
     * @warning
     * The behavior is undefined if the handle doesn't contain a resource.
     *
     * @return A pointer to the managed resource or `nullptr` if the handle
     * contains no resource at all.
     */
    [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
        return resource.get();
    }

    /**
     * @brief Returns true if a handle contains a resource, false otherwise.
     * @return True if the handle contains a resource, false otherwise.
     */
    [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
        return static_cast<bool>(resource);
    }

    /**
     * @brief Returns the number of handles pointing the same resource.
     * @return The number of handles pointing the same resource.
     */
    [[nodiscard]] size_type use_count() const ENTT_NOEXCEPT {
        return resource.use_count();
    }

private:
    std::shared_ptr<value_type> resource;
};

/**
 * @brief Compares two handles.
 * @tparam Res Type of resource managed by the first handle.
 * @tparam Other Type of resource managed by the second handle.
 * @param lhs A valid handle.
 * @param rhs A valid handle.
 * @return True if both handles refer to the same resource, false otherwise.
 */
template<typename Res, typename Other>
[[nodiscard]] bool operator==(const resource_handle<Res> &lhs, const resource_handle<Other> &rhs) ENTT_NOEXCEPT {
    return lhs.operator->() == rhs.operator->();
}

template<typename ILhs, typename IRhs>
[[nodiscard]] bool operator!=(const resource_handle<ILhs> &lhs, const resource_handle<IRhs> &rhs) ENTT_NOEXCEPT {
    return !(lhs == rhs);
}

} // namespace entt

#endif
<commit_msg>resource_handle: updated doc<commit_after>#ifndef ENTT_RESOURCE_HANDLE_HPP
#define ENTT_RESOURCE_HANDLE_HPP

#include <memory>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "fwd.hpp"

namespace entt {

/**
 * @brief Shared resource handle.
 *
 * A shared resource handle is a small class that wraps a resource and keeps it
 * alive even if it's deleted from the cache. It can be either copied or
 * moved. A handle shares a reference to the same resource with all the other
 * handles constructed for the same identifier.

 * As a rule of thumb, resources should never be copied nor moved. Handles are
 * the way to go to keep references to them.
 *
 * @tparam Resource Type of resource managed by a handle.
 */
template<typename Resource>
class resource_handle {
    /*! @brief Resource handles are friends with each other. */
    template<typename>
    friend class resource_handle;

public:
    /*! @brief Value type. */
    using value_type = Resource;
    /*! @brief Reference type. */
    using reference = value_type &;
    /*! @brief Pointer type. */
    using pointer = value_type *;
    /*! @brief Unsigned integer type. */
    using size_type = long;

    /*! @brief Default constructor. */
    resource_handle() ENTT_NOEXCEPT = default;

    /**
     * @brief Creates a handle from a shared pointer, namely a resource.
     * @param res A pointer to a properly initialized resource.
     */
    resource_handle(std::shared_ptr<value_type> res) ENTT_NOEXCEPT
        : resource{std::move(res)} {}

    /**
     * @brief Copy constructor.
     * @param other The instance to copy from.
     */
    resource_handle(const resource_handle &other) ENTT_NOEXCEPT = default;

    /**
     * @brief Move constructor.
     * @param other The instance to move from.
     */
    resource_handle(resource_handle &&other) ENTT_NOEXCEPT = default;

    /**
     * @brief Aliasing constructor.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle with which to share ownership information.
     * @param res Unrelated and unmanaged resources.
     */
    template<typename Other>
    resource_handle(const resource_handle<Other> &other, value_type &res) ENTT_NOEXCEPT
        : resource{other.resource, std::addressof(res)} {}

    /**
     * @brief Copy constructs a handle which shares ownership of the resource.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to copy from.
     */
    template<typename Other, typename = std::enable_if_t<!std::is_same_v<value_type, Other> && std::is_base_of_v<value_type, Other>>>
    resource_handle(const resource_handle<Other> &other) ENTT_NOEXCEPT
        : resource{other.resource} {}

    /**
     * @brief Move constructs a handle which takes ownership of the resource.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to move from.
     */
    template<typename Other, typename = std::enable_if_t<!std::is_same_v<value_type, Other> && std::is_base_of_v<value_type, Other>>>
    resource_handle(resource_handle<Other> &&other) ENTT_NOEXCEPT
        : resource{std::move(other.resource)} {}

    /**
     * @brief Copy assignment operator.
     * @param other The instance to copy from.
     * @return This resource handle.
     */
    resource_handle &operator=(const resource_handle &other) ENTT_NOEXCEPT = default;

    /**
     * @brief Move assignment operator.
     * @param other The instance to move from.
     * @return This resource handle.
     */
    resource_handle &operator=(resource_handle &&other) ENTT_NOEXCEPT = default;

    /**
     * @brief Copy assignment operator from foreign handle.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to copy from.
     * @return This resource handle.
     */
    template<typename Other>
    std::enable_if_t<!std::is_same_v<value_type, Other> && std::is_base_of_v<value_type, Other>, resource_handle &>
    operator=(const resource_handle<Other> &other) ENTT_NOEXCEPT {
        resource = other.resource;
        return *this;
    }

    /**
     * @brief Move assignment operator from foreign handle.
     * @tparam Other Type of resource managed by the received handle.
     * @param other The handle to move from.
     * @return This resource handle.
     */
    template<typename Other>
    std::enable_if_t<!std::is_same_v<value_type, Other> && std::is_base_of_v<value_type, Other>, resource_handle &>
    operator=(resource_handle<Other> &&other) ENTT_NOEXCEPT {
        resource = std::move(other.resource);
        return *this;
    }

    /**
     * @brief Gets a reference to the managed resource.
     *
     * @warning
     * The behavior is undefined if the handle doesn't contain a resource.
     *
     * @return A reference to the managed resource.
     */
    [[nodiscard]] reference get() const ENTT_NOEXCEPT {
        return *resource;
    }

    /*! @copydoc get */
    [[nodiscard]] operator reference() const ENTT_NOEXCEPT {
        return get();
    }

    /*! @copydoc get */
    [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
        return get();
    }

    /**
     * @brief Gets a pointer to the managed resource.
     *
     * @warning
     * The behavior is undefined if the handle doesn't contain a resource.
     *
     * @return A pointer to the managed resource or `nullptr` if the handle
     * contains no resource at all.
     */
    [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
        return resource.get();
    }

    /**
     * @brief Returns true if a handle contains a resource, false otherwise.
     * @return True if the handle contains a resource, false otherwise.
     */
    [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
        return static_cast<bool>(resource);
    }

    /**
     * @brief Returns the number of handles pointing the same resource.
     * @return The number of handles pointing the same resource.
     */
    [[nodiscard]] size_type use_count() const ENTT_NOEXCEPT {
        return resource.use_count();
    }

private:
    std::shared_ptr<value_type> resource;
};

/**
 * @brief Compares two handles.
 * @tparam Res Type of resource managed by the first handle.
 * @tparam Other Type of resource managed by the second handle.
 * @param lhs A valid handle.
 * @param rhs A valid handle.
 * @return True if both handles refer to the same resource, false otherwise.
 */
template<typename Res, typename Other>
[[nodiscard]] bool operator==(const resource_handle<Res> &lhs, const resource_handle<Other> &rhs) ENTT_NOEXCEPT {
    return lhs.operator->() == rhs.operator->();
}

/**
 * @brief Compares two handles.
 * @tparam Res Type of resource managed by the first handle.
 * @tparam Other Type of resource managed by the second handle.
 * @param lhs A valid handle.
 * @param rhs A valid handle.
 * @return False if both handles refer to the same registry, true otherwise.
 */
template<typename ILhs, typename IRhs>
[[nodiscard]] bool operator!=(const resource_handle<ILhs> &lhs, const resource_handle<IRhs> &rhs) ENTT_NOEXCEPT {
    return !(lhs == rhs);
}

} // namespace entt

#endif
<|endoftext|>


<commit_before>// $Id: fe_hermite_shape_1D.C,v 1.1 2005-08-25 18:31:37 roystgnr Exp $

// The libMesh Finite Element Library.
// Copyright (C) 2002-2005  Benjamin S. Kirk, John W. Peterson

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

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ inlcludes

// Local includes
#include "fe.h"
#include "elem.h"

// Anonymous namespace for persistant variables.
// This allows us to cache the global-to-local mapping transformation
// This should also screw up multithreading royally
namespace
{
  static unsigned int old_elem_id = libMesh::invalid_uint;
  // Coefficient naming: d(1)d(2n) is the coefficient of the
  // global shape function corresponding to value 1 in terms of the
  // local shape function corresponding to normal derivative 2
  static Real d1xd1x, d2xd2x;

// Compute the static coefficients for an element
void hermite_compute_coefs(const Elem* elem)
{
  // Coefficients are cached from old elements
  if (elem->id() == old_elem_id)
    return;

  old_elem_id = elem->id();

  const Order mapping_order        (elem->default_order());
  const ElemType mapping_elem_type (elem->type());
  const int n_mapping_shape_functions =
    FE<1,LAGRANGE>::n_shape_functions(mapping_elem_type,
				      mapping_order);

  // Degrees of freedom are at vertices and edge midpoints
  std::vector<Point> dofpt;
  dofpt.push_back(Point(0));
  dofpt.push_back(Point(1));

  // Mapping functions - first derivatives at each dofpt
  std::vector<Real> dxdxi(2);
  std::vector<Real> dxidx(2);

  for (int p = 0; p != 2; ++p)
    {
      for (int i = 0; i != n_mapping_shape_functions; ++i)
        {
          const Real ddxi = FE<1,LAGRANGE>::shape_deriv
            (mapping_elem_type, mapping_order, i, 0, dofpt[p]);
          dxdxi[p] += dofpt[p](0) * ddxi;
        }
    }

  // Calculate derivative scaling factors

  d1xd1x = dxdxi[0];
  d2xd2x = dxdxi[1];
}

} // end anonymous namespace

  // Return shape function second derivatives on the unit right
  // triangle
Real hermite_raw_shape_second_deriv(const unsigned int basis_num,
                                    const Real xi)
{
  switch (basis_num)
    {
      case 0:
        return -6 + 12*xi;
      case 1:
        return 6 - 12*xi;
      case 2:
        return -4 + 6*xi;
      case 3:
        return -2 + 6*xi;
    }

  error();
  return 0.;
}

Real hermite_raw_shape_deriv(const unsigned int basis_num,
                             const Real xi)
{
  switch (basis_num)
    {
      case 0:
        return -6*xi + 6*xi*xi;
      case 1:
        return 6*xi - 6*xi*xi;
      case 2:
        return 1 - 4*xi + 3*xi*xi;
      case 3:
        return -2*xi + 3*xi*xi;
    }

  error();
  return 0.;
}

Real hermite_raw_shape(const unsigned int basis_num,
                       const Real xi)
{
  switch (basis_num)
    {
      case 0:
        return 1 - 3*xi*xi + 2*xi*xi*xi;
      case 1:
        return 3*xi*xi - 2*xi*xi*xi;
      case 2:
        return xi - 2*xi*xi + xi*xi*xi;
      case 3:
        return -xi*xi + xi*xi*xi;
    }

  error();
  return 0.;
}

template <>
Real FE<1,HERMITE>::shape(const ElemType,
			  const Order,
			  const unsigned int,
			  const Point&)
{
  std::cerr << "Hermite elements require the real element\n"
	    << "to construct gradient-based degrees of freedom."
	    << std::endl;

  error();
  return 0.;
}

template <>
Real FE<1,HERMITE>::shape(const Elem* elem,
			  const Order order,
			  const unsigned int i,
			  const Point& p)
{
  assert (elem != NULL);

  hermite_compute_coefs(elem);

  const ElemType type = elem->type();

  switch (order)
    {
      // Hermite cubic shape functions
    case THIRD:
      {
	switch (type)
	  {
	    // C1 functions on the C1 cubic edge
	  case EDGE2:
	  case EDGE3:
	    {
	      assert (i<4);

	      switch (i)
		{
		case 0:
		  return hermite_raw_shape(0, p(0));
		case 1:
		  return d1xd1x * hermite_raw_shape(2, p(0));
		case 2:
		  return hermite_raw_shape(1, p(0));
		case 3:
                  return d2xd2x * hermite_raw_shape(3, p(0));
		default:
		  error();
		}
	    }
	  default:
            std::cerr << "ERROR: Unsupported element type!" << std::endl;
	    error();
	  }
      }
      // by default throw an error
    default:
      std::cerr << "ERROR: Unsupported polynomial order!" << std::endl;
      error();
    }

  error();
  return 0.;
}

template <>
Real FE<1,HERMITE>::shape_deriv(const ElemType,
				const Order,
				const unsigned int,
				const unsigned int,
				const Point&)
{
  std::cerr << "Hermite elements require the real element\n"
	    << "to construct gradient-based degrees of freedom."
	    << std::endl;

  error();
  return 0.;
}

template <>
Real FE<1,HERMITE>::shape_deriv(const Elem* elem,
				const Order order,
				const unsigned int i,
				const unsigned int j,
				const Point& p)
{
  assert (elem != NULL);

  hermite_compute_coefs(elem);

  const ElemType type = elem->type();

  switch (order)
    {
      // Hermite cubic shape functions
    case THIRD:
      {
	switch (type)
	  {
	    // C1 functions on the C1 cubic edge
	  case EDGE2:
	  case EDGE3:
	    {
	      switch (i)
		{
		case 0:
		  return hermite_raw_shape_deriv(0, p(0));
		case 1:
		  return d1xd1x * hermite_raw_shape_deriv(2, p(0));
		case 2:
		  return hermite_raw_shape_deriv(1, p(0));
		case 3:
                  return d2xd2x * hermite_raw_shape_deriv(3, p(0));
		default:
		  error();
		}
	    }
	  default:
            std::cerr << "ERROR: Unsupported element type!" << std::endl;
	    error();
	  }
      }
      // by default throw an error
    default:
      std::cerr << "ERROR: Unsupported polynomial order!" << std::endl;
      error();
    }

  error();
  return 0.;
}

template <>
Real FE<1,HERMITE>::shape_second_deriv(const Elem* elem,
                                       const Order order,
                                       const unsigned int i,
                                       const unsigned int j,
                                       const Point& p)
{
  assert (elem != NULL);

  hermite_compute_coefs(elem);

  const ElemType type = elem->type();

  switch (order)
    {
      // Hermite cubic shape functions
    case THIRD:
      {
	switch (type)
	  {
	    // C1 functions on the C1 cubic edge
	  case EDGE2:
	  case EDGE3:
	    {
	      switch (i)
		{
		case 0:
		  return hermite_raw_shape_second_deriv(0, p(0));
		case 1:
		  return d1xd1x * hermite_raw_shape_second_deriv(2, p(0));
		case 2:
		  return hermite_raw_shape_second_deriv(1, p(0));
		case 3:
                  return d2xd2x * hermite_raw_shape_second_deriv(3, p(0));
		default:
		  error();
		}
	    }
	  default:
            std::cerr << "ERROR: Unsupported element type!" << std::endl;
	    error();
	  }
      }
      // by default throw an error
    default:
      std::cerr << "ERROR: Unsupported polynomial order!" << std::endl;
      error();
    }

  error();
  return 0.;
}
<commit_msg>Fixed linker errors<commit_after>// $Id: fe_hermite_shape_1D.C,v 1.2 2005-08-25 19:07:15 roystgnr Exp $

// The libMesh Finite Element Library.
// Copyright (C) 2002-2005  Benjamin S. Kirk, John W. Peterson

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

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ inlcludes

// Local includes
#include "fe.h"
#include "elem.h"

// Anonymous namespace for persistant variables.
// This allows us to cache the global-to-local mapping transformation
// This should also screw up multithreading royally
namespace
{
  static unsigned int old_elem_id = libMesh::invalid_uint;
  // Coefficient naming: d(1)d(2n) is the coefficient of the
  // global shape function corresponding to value 1 in terms of the
  // local shape function corresponding to normal derivative 2
  static Real d1xd1x, d2xd2x;

// Compute the static coefficients for an element
void hermite_compute_coefs(const Elem* elem)
{
  // Coefficients are cached from old elements
  if (elem->id() == old_elem_id)
    return;

  old_elem_id = elem->id();

  const Order mapping_order        (elem->default_order());
  const ElemType mapping_elem_type (elem->type());
  const int n_mapping_shape_functions =
    FE<1,LAGRANGE>::n_shape_functions(mapping_elem_type,
				      mapping_order);

  // Degrees of freedom are at vertices and edge midpoints
  std::vector<Point> dofpt;
  dofpt.push_back(Point(0));
  dofpt.push_back(Point(1));

  // Mapping functions - first derivatives at each dofpt
  std::vector<Real> dxdxi(2);
  std::vector<Real> dxidx(2);

  for (int p = 0; p != 2; ++p)
    {
      for (int i = 0; i != n_mapping_shape_functions; ++i)
        {
          const Real ddxi = FE<1,LAGRANGE>::shape_deriv
            (mapping_elem_type, mapping_order, i, 0, dofpt[p]);
          dxdxi[p] += dofpt[p](0) * ddxi;
        }
    }

  // Calculate derivative scaling factors

  d1xd1x = dxdxi[0];
  d2xd2x = dxdxi[1];
}

} // end anonymous namespace

template<>
Real FEHermite<1>::hermite_raw_shape_second_deriv
 (const unsigned int basis_num, const Real xi)
{
  switch (basis_num)
    {
      case 0:
        return -6 + 12*xi;
      case 1:
        return 6 - 12*xi;
      case 2:
        return -4 + 6*xi;
      case 3:
        return -2 + 6*xi;
    }

  error();
  return 0.;
}

template<>
Real FEHermite<1>::hermite_raw_shape_deriv
 (const unsigned int basis_num, const Real xi)
{
  switch (basis_num)
    {
      case 0:
        return -6*xi + 6*xi*xi;
      case 1:
        return 6*xi - 6*xi*xi;
      case 2:
        return 1 - 4*xi + 3*xi*xi;
      case 3:
        return -2*xi + 3*xi*xi;
    }

  error();
  return 0.;
}

template<>
Real FEHermite<1>::hermite_raw_shape
 (const unsigned int basis_num, const Real xi)
{
  switch (basis_num)
    {
      case 0:
        return 1 - 3*xi*xi + 2*xi*xi*xi;
      case 1:
        return 3*xi*xi - 2*xi*xi*xi;
      case 2:
        return xi - 2*xi*xi + xi*xi*xi;
      case 3:
        return -xi*xi + xi*xi*xi;
    }

  error();
  return 0.;
}

template <>
Real FE<1,HERMITE>::shape(const ElemType,
			  const Order,
			  const unsigned int,
			  const Point&)
{
  std::cerr << "Hermite elements require the real element\n"
	    << "to construct gradient-based degrees of freedom."
	    << std::endl;

  error();
  return 0.;
}

template <>
Real FE<1,HERMITE>::shape(const Elem* elem,
			  const Order order,
			  const unsigned int i,
			  const Point& p)
{
  assert (elem != NULL);

  hermite_compute_coefs(elem);

  const ElemType type = elem->type();

  switch (order)
    {
      // Hermite cubic shape functions
    case THIRD:
      {
	switch (type)
	  {
	    // C1 functions on the C1 cubic edge
	  case EDGE2:
	  case EDGE3:
	    {
	      assert (i<4);

	      switch (i)
		{
		case 0:
		  return FEHermite<1>::hermite_raw_shape(0, p(0));
		case 1:
		  return d1xd1x * FEHermite<1>::hermite_raw_shape(2, p(0));
		case 2:
		  return FEHermite<1>::hermite_raw_shape(1, p(0));
		case 3:
                  return d2xd2x * FEHermite<1>::hermite_raw_shape(3, p(0));
		default:
		  error();
		}
	    }
	  default:
            std::cerr << "ERROR: Unsupported element type!" << std::endl;
	    error();
	  }
      }
      // by default throw an error
    default:
      std::cerr << "ERROR: Unsupported polynomial order!" << std::endl;
      error();
    }

  error();
  return 0.;
}

template <>
Real FE<1,HERMITE>::shape_deriv(const ElemType,
				const Order,
				const unsigned int,
				const unsigned int,
				const Point&)
{
  std::cerr << "Hermite elements require the real element\n"
	    << "to construct gradient-based degrees of freedom."
	    << std::endl;

  error();
  return 0.;
}

template <>
Real FE<1,HERMITE>::shape_deriv(const Elem* elem,
				const Order order,
				const unsigned int i,
				const unsigned int,
				const Point& p)
{
  assert (elem != NULL);

  hermite_compute_coefs(elem);

  const ElemType type = elem->type();

  switch (order)
    {
      // Hermite cubic shape functions
    case THIRD:
      {
	switch (type)
	  {
	    // C1 functions on the C1 cubic edge
	  case EDGE2:
	  case EDGE3:
	    {
	      switch (i)
		{
		case 0:
		  return FEHermite<1>::hermite_raw_shape_deriv(0, p(0));
		case 1:
		  return d1xd1x * FEHermite<1>::hermite_raw_shape_deriv(2, p(0));
		case 2:
		  return FEHermite<1>::hermite_raw_shape_deriv(1, p(0));
		case 3:
                  return d2xd2x * FEHermite<1>::hermite_raw_shape_deriv(3, p(0));
		default:
		  error();
		}
	    }
	  default:
            std::cerr << "ERROR: Unsupported element type!" << std::endl;
	    error();
	  }
      }
      // by default throw an error
    default:
      std::cerr << "ERROR: Unsupported polynomial order!" << std::endl;
      error();
    }

  error();
  return 0.;
}

template <>
Real FE<1,HERMITE>::shape_second_deriv(const Elem* elem,
                                       const Order order,
                                       const unsigned int i,
                                       const unsigned int,
                                       const Point& p)
{
  assert (elem != NULL);

  hermite_compute_coefs(elem);

  const ElemType type = elem->type();

  switch (order)
    {
      // Hermite cubic shape functions
    case THIRD:
      {
	switch (type)
	  {
	    // C1 functions on the C1 cubic edge
	  case EDGE2:
	  case EDGE3:
	    {
	      switch (i)
		{
		case 0:
		  return FEHermite<1>::hermite_raw_shape_second_deriv(0, p(0));
		case 1:
		  return d1xd1x * FEHermite<1>::hermite_raw_shape_second_deriv(2, p(0));
		case 2:
		  return FEHermite<1>::hermite_raw_shape_second_deriv(1, p(0));
		case 3:
                  return d2xd2x * FEHermite<1>::hermite_raw_shape_second_deriv(3, p(0));
		default:
		  error();
		}
	    }
	  default:
            std::cerr << "ERROR: Unsupported element type!" << std::endl;
	    error();
	  }
      }
      // by default throw an error
    default:
      std::cerr << "ERROR: Unsupported polynomial order!" << std::endl;
      error();
    }

  error();
  return 0.;
}
<|endoftext|>