<commit_before>/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include "core/css/resolver/SharedStyleFinder.h"

#include "HTMLNames.h"
#include "XMLNames.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/css/resolver/StyleResolverStats.h"
#include "core/dom/ContainerNode.h"
#include "core/dom/Document.h"
#include "core/dom/ElementTraversal.h"
#include "core/dom/FullscreenElementStack.h"
#include "core/dom/Node.h"
#include "core/dom/NodeRenderStyle.h"
#include "core/dom/QualifiedName.h"
#include "core/dom/SpaceSplitString.h"
#include "core/dom/shadow/ElementShadow.h"
#include "core/dom/shadow/InsertionPoint.h"
#include "core/html/HTMLElement.h"
#include "core/html/HTMLInputElement.h"
#include "core/html/HTMLOptGroupElement.h"
#include "core/html/HTMLOptionElement.h"
#include "core/rendering/style/RenderStyle.h"
#include "core/svg/SVGElement.h"
#include "wtf/HashSet.h"
#include "wtf/text/AtomicString.h"

namespace WebCore {

using namespace HTMLNames;

bool SharedStyleFinder::canShareStyleWithControl(Element& candidate) const
{
    if (!isHTMLInputElement(candidate) || !isHTMLInputElement(element()))
        return false;

    HTMLInputElement& candidateInput = toHTMLInputElement(candidate);
    HTMLInputElement& thisInput = toHTMLInputElement(element());

    if (candidateInput.isAutofilled() != thisInput.isAutofilled())
        return false;
    if (candidateInput.shouldAppearChecked() != thisInput.shouldAppearChecked())
        return false;
    if (candidateInput.shouldAppearIndeterminate() != thisInput.shouldAppearIndeterminate())
        return false;
    if (candidateInput.isRequired() != thisInput.isRequired())
        return false;

    if (candidate.isDisabledFormControl() != element().isDisabledFormControl())
        return false;

    if (candidate.isDefaultButtonForForm() != element().isDefaultButtonForForm())
        return false;

    if (document().containsValidityStyleRules()) {
        bool willValidate = candidate.willValidate();

        if (willValidate != element().willValidate())
            return false;

        if (willValidate && (candidate.isValidFormControlElement() != element().isValidFormControlElement()))
            return false;

        if (candidate.isInRange() != element().isInRange())
            return false;

        if (candidate.isOutOfRange() != element().isOutOfRange())
            return false;
    }

    return true;
}

bool SharedStyleFinder::classNamesAffectedByRules(const SpaceSplitString& classNames) const
{
    unsigned count = classNames.size();
    for (unsigned i = 0; i < count; ++i) {
        if (m_features.hasSelectorForClass(classNames[i]))
            return true;
    }
    return false;
}

static inline const AtomicString& typeAttributeValue(const Element& element)
{
    // type is animatable in SVG so we need to go down the slow path here.
    return element.isSVGElement() ? element.getAttribute(typeAttr) : element.fastGetAttribute(typeAttr);
}

bool SharedStyleFinder::sharingCandidateHasIdenticalStyleAffectingAttributes(Element& candidate) const
{
    if (element().elementData() == candidate.elementData())
        return true;
    if (element().fastGetAttribute(XMLNames::langAttr) != candidate.fastGetAttribute(XMLNames::langAttr))
        return false;
    if (element().fastGetAttribute(langAttr) != candidate.fastGetAttribute(langAttr))
        return false;

    // These two checks must be here since RuleSet has a special case to allow style sharing between elements
    // with type and readonly attributes whereas other attribute selectors prevent sharing.
    if (typeAttributeValue(element()) != typeAttributeValue(candidate))
        return false;
    if (element().fastGetAttribute(readonlyAttr) != candidate.fastGetAttribute(readonlyAttr))
        return false;

    if (!m_elementAffectedByClassRules) {
        if (candidate.hasClass() && classNamesAffectedByRules(candidate.classNames()))
            return false;
    } else if (candidate.hasClass()) {
        // SVG elements require a (slow!) getAttribute comparision because "class" is an animatable attribute for SVG.
        if (element().isSVGElement()) {
            if (element().getAttribute(classAttr) != candidate.getAttribute(classAttr))
                return false;
        } else if (element().classNames() != candidate.classNames()) {
            return false;
        }
    } else {
        return false;
    }

    if (element().presentationAttributeStyle() != candidate.presentationAttributeStyle())
        return false;

    // FIXME: Consider removing this, it's unlikely we'll have so many progress elements
    // that sharing the style makes sense. Instead we should just not support style sharing
    // for them.
    if (isHTMLProgressElement(element())) {
        if (element().shouldAppearIndeterminate() != candidate.shouldAppearIndeterminate())
            return false;
    }

    if (isHTMLOptGroupElement(element()) || isHTMLOptionElement(element())) {
        if (element().isDisabledFormControl() != candidate.isDisabledFormControl())
            return false;
        if (isHTMLOptionElement(element()) && toHTMLOptionElement(element()).selected() != toHTMLOptionElement(candidate).selected())
            return false;
    }

    return true;
}

bool SharedStyleFinder::sharingCandidateShadowHasSharedStyleSheetContents(Element& candidate) const
{
    if (!element().shadow() || !element().shadow()->containsActiveStyles())
        return false;

    return element().shadow()->hasSameStyles(candidate.shadow());
}

bool SharedStyleFinder::sharingCandidateDistributedToSameInsertionPoint(Element& candidate) const
{
    Vector<InsertionPoint*, 8> insertionPoints, candidateInsertionPoints;
    collectDestinationInsertionPoints(element(), insertionPoints);
    collectDestinationInsertionPoints(candidate, candidateInsertionPoints);
    if (insertionPoints.size() != candidateInsertionPoints.size())
        return false;
    for (size_t i = 0; i < insertionPoints.size(); ++i) {
        if (insertionPoints[i] != candidateInsertionPoints[i])
            return false;
    }
    return true;
}

bool SharedStyleFinder::canShareStyleWithElement(Element& candidate) const
{
    if (element() == candidate)
        return false;
    Element* parent = candidate.parentOrShadowHostElement();
    RenderStyle* style = candidate.renderStyle();
    if (!style)
        return false;
    if (!style->isSharable())
        return false;
    if (!parent)
        return false;
    if (element().parentOrShadowHostElement()->renderStyle() != parent->renderStyle())
        return false;
    if (candidate.tagQName() != element().tagQName())
        return false;
    if (candidate.inlineStyle())
        return false;
    if (candidate.needsStyleRecalc())
        return false;
    if (candidate.isSVGElement() && toSVGElement(candidate).animatedSMILStyleProperties())
        return false;
    if (candidate.isLink() != element().isLink())
        return false;
    if (candidate.hovered() != element().hovered())
        return false;
    if (candidate.active() != element().active())
        return false;
    if (candidate.focused() != element().focused())
        return false;
    if (candidate.shadowPseudoId() != element().shadowPseudoId())
        return false;
    if (candidate == document().cssTarget())
        return false;
    if (!sharingCandidateHasIdenticalStyleAffectingAttributes(candidate))
        return false;
    if (candidate.additionalPresentationAttributeStyle() != element().additionalPresentationAttributeStyle())
        return false;
    if (candidate.hasID() && m_features.hasSelectorForId(candidate.idForStyleResolution()))
        return false;
    if (candidate.hasScopedHTMLStyleChild())
        return false;
    if (candidate.shadow() && candidate.shadow()->containsActiveStyles() && !sharingCandidateShadowHasSharedStyleSheetContents(candidate))
        return false;
    if (!sharingCandidateDistributedToSameInsertionPoint(candidate))
        return false;
    if (candidate.isInTopLayer() != element().isInTopLayer())
        return false;

    bool isControl = candidate.isFormControlElement();

    if (isControl != element().isFormControlElement())
        return false;

    if (isControl && !canShareStyleWithControl(candidate))
        return false;

    // FIXME: This line is surprisingly hot, we may wish to inline hasDirectionAuto into StyleResolver.
    if (candidate.isHTMLElement() && toHTMLElement(candidate).hasDirectionAuto())
        return false;

    if (candidate.isLink() && m_context.elementLinkState() != style->insideLink())
        return false;

    if (candidate.isUnresolvedCustomElement() != element().isUnresolvedCustomElement())
        return false;

    if (element().parentOrShadowHostElement() != parent) {
        if (!parent->isStyledElement())
            return false;
        if (parent->hasScopedHTMLStyleChild())
            return false;
        if (parent->inlineStyle())
            return false;
        if (parent->isSVGElement() && toSVGElement(parent)->animatedSMILStyleProperties())
            return false;
        if (parent->hasID() && m_features.hasSelectorForId(parent->idForStyleResolution()))
            return false;
        if (!parent->childrenSupportStyleSharing())
            return false;
    }

    return true;
}

bool SharedStyleFinder::documentContainsValidCandidate() const
{
    for (Element* element = document().documentElement(); element; element = ElementTraversal::next(*element)) {
        if (element->supportsStyleSharing() && canShareStyleWithElement(*element))
            return true;
    }
    return false;
}

inline Element* SharedStyleFinder::findElementForStyleSharing() const
{
    StyleSharingList& styleSharingList = m_styleResolver.styleSharingList();
    for (StyleSharingList::iterator it = styleSharingList.begin(); it != styleSharingList.end(); ++it) {
        Element& candidate = **it;
        if (!canShareStyleWithElement(candidate))
            continue;
        if (it != styleSharingList.begin()) {
            // Move the element to the front of the LRU
            styleSharingList.remove(it);
            styleSharingList.prepend(&candidate);
        }
        return &candidate;
    }
    m_styleResolver.addToStyleSharingList(element());
    return 0;
}

bool SharedStyleFinder::matchesRuleSet(RuleSet* ruleSet)
{
    if (!ruleSet)
        return false;
    ElementRuleCollector collector(m_context, m_styleResolver.selectorFilter());
    return collector.hasAnyMatchingRules(ruleSet);
}

RenderStyle* SharedStyleFinder::findSharedStyle()
{
    INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleLookups);

    if (!element().supportsStyleSharing())
        return 0;

    // Cache whether context.element() is affected by any known class selectors.
    m_elementAffectedByClassRules = element().hasClass() && classNamesAffectedByRules(element().classNames());

    Element* shareElement = findElementForStyleSharing();

    if (!shareElement) {
        if (m_styleResolver.stats() && m_styleResolver.stats()->printMissedCandidateCount && documentContainsValidCandidate())
            INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleMissed);
        return 0;
    }

    INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleFound);

    if (matchesRuleSet(m_siblingRuleSet)) {
        INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleRejectedBySiblingRules);
        return 0;
    }

    if (matchesRuleSet(m_uncommonAttributeRuleSet)) {
        INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleRejectedByUncommonAttributeRules);
        return 0;
    }

    // Tracking child index requires unique style for each node. This may get set by the sibling rule match above.
    if (!element().parentElementOrShadowRoot()->childrenSupportStyleSharing()) {
        INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleRejectedByParent);
        return 0;
    }

    return shareElement->renderStyle();
}

}
<commit_msg>Remove some checks from SharedStyleFinder<commit_after>/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include "core/css/resolver/SharedStyleFinder.h"

#include "HTMLNames.h"
#include "XMLNames.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/css/resolver/StyleResolverStats.h"
#include "core/dom/ContainerNode.h"
#include "core/dom/Document.h"
#include "core/dom/ElementTraversal.h"
#include "core/dom/FullscreenElementStack.h"
#include "core/dom/Node.h"
#include "core/dom/NodeRenderStyle.h"
#include "core/dom/QualifiedName.h"
#include "core/dom/SpaceSplitString.h"
#include "core/dom/shadow/ElementShadow.h"
#include "core/dom/shadow/InsertionPoint.h"
#include "core/html/HTMLElement.h"
#include "core/html/HTMLInputElement.h"
#include "core/html/HTMLOptGroupElement.h"
#include "core/html/HTMLOptionElement.h"
#include "core/rendering/style/RenderStyle.h"
#include "core/svg/SVGElement.h"
#include "wtf/HashSet.h"
#include "wtf/text/AtomicString.h"

namespace WebCore {

using namespace HTMLNames;

bool SharedStyleFinder::canShareStyleWithControl(Element& candidate) const
{
    if (!isHTMLInputElement(candidate) || !isHTMLInputElement(element()))
        return false;

    HTMLInputElement& candidateInput = toHTMLInputElement(candidate);
    HTMLInputElement& thisInput = toHTMLInputElement(element());

    if (candidateInput.isAutofilled() != thisInput.isAutofilled())
        return false;
    if (candidateInput.shouldAppearChecked() != thisInput.shouldAppearChecked())
        return false;
    if (candidateInput.shouldAppearIndeterminate() != thisInput.shouldAppearIndeterminate())
        return false;
    if (candidateInput.isRequired() != thisInput.isRequired())
        return false;

    if (candidate.isDisabledFormControl() != element().isDisabledFormControl())
        return false;

    if (candidate.isDefaultButtonForForm() != element().isDefaultButtonForForm())
        return false;

    if (document().containsValidityStyleRules()) {
        bool willValidate = candidate.willValidate();

        if (willValidate != element().willValidate())
            return false;

        if (willValidate && (candidate.isValidFormControlElement() != element().isValidFormControlElement()))
            return false;

        if (candidate.isInRange() != element().isInRange())
            return false;

        if (candidate.isOutOfRange() != element().isOutOfRange())
            return false;
    }

    return true;
}

bool SharedStyleFinder::classNamesAffectedByRules(const SpaceSplitString& classNames) const
{
    unsigned count = classNames.size();
    for (unsigned i = 0; i < count; ++i) {
        if (m_features.hasSelectorForClass(classNames[i]))
            return true;
    }
    return false;
}

static inline const AtomicString& typeAttributeValue(const Element& element)
{
    // type is animatable in SVG so we need to go down the slow path here.
    return element.isSVGElement() ? element.getAttribute(typeAttr) : element.fastGetAttribute(typeAttr);
}

bool SharedStyleFinder::sharingCandidateHasIdenticalStyleAffectingAttributes(Element& candidate) const
{
    if (element().elementData() == candidate.elementData())
        return true;
    if (element().fastGetAttribute(XMLNames::langAttr) != candidate.fastGetAttribute(XMLNames::langAttr))
        return false;
    if (element().fastGetAttribute(langAttr) != candidate.fastGetAttribute(langAttr))
        return false;

    // These two checks must be here since RuleSet has a special case to allow style sharing between elements
    // with type and readonly attributes whereas other attribute selectors prevent sharing.
    if (typeAttributeValue(element()) != typeAttributeValue(candidate))
        return false;
    if (element().fastGetAttribute(readonlyAttr) != candidate.fastGetAttribute(readonlyAttr))
        return false;

    if (!m_elementAffectedByClassRules) {
        if (candidate.hasClass() && classNamesAffectedByRules(candidate.classNames()))
            return false;
    } else if (candidate.hasClass()) {
        // SVG elements require a (slow!) getAttribute comparision because "class" is an animatable attribute for SVG.
        if (element().isSVGElement()) {
            if (element().getAttribute(classAttr) != candidate.getAttribute(classAttr))
                return false;
        } else if (element().classNames() != candidate.classNames()) {
            return false;
        }
    } else {
        return false;
    }

    if (element().presentationAttributeStyle() != candidate.presentationAttributeStyle())
        return false;

    // FIXME: Consider removing this, it's unlikely we'll have so many progress elements
    // that sharing the style makes sense. Instead we should just not support style sharing
    // for them.
    if (isHTMLProgressElement(element())) {
        if (element().shouldAppearIndeterminate() != candidate.shouldAppearIndeterminate())
            return false;
    }

    if (isHTMLOptGroupElement(element()) || isHTMLOptionElement(element())) {
        if (element().isDisabledFormControl() != candidate.isDisabledFormControl())
            return false;
        if (isHTMLOptionElement(element()) && toHTMLOptionElement(element()).selected() != toHTMLOptionElement(candidate).selected())
            return false;
    }

    return true;
}

bool SharedStyleFinder::sharingCandidateShadowHasSharedStyleSheetContents(Element& candidate) const
{
    if (!element().shadow() || !element().shadow()->containsActiveStyles())
        return false;

    return element().shadow()->hasSameStyles(candidate.shadow());
}

bool SharedStyleFinder::sharingCandidateDistributedToSameInsertionPoint(Element& candidate) const
{
    Vector<InsertionPoint*, 8> insertionPoints, candidateInsertionPoints;
    collectDestinationInsertionPoints(element(), insertionPoints);
    collectDestinationInsertionPoints(candidate, candidateInsertionPoints);
    if (insertionPoints.size() != candidateInsertionPoints.size())
        return false;
    for (size_t i = 0; i < insertionPoints.size(); ++i) {
        if (insertionPoints[i] != candidateInsertionPoints[i])
            return false;
    }
    return true;
}

bool SharedStyleFinder::canShareStyleWithElement(Element& candidate) const
{
    if (element() == candidate)
        return false;
    Element* parent = candidate.parentOrShadowHostElement();
    RenderStyle* style = candidate.renderStyle();
    if (!style)
        return false;
    if (!style->isSharable())
        return false;
    if (!parent)
        return false;
    if (element().parentOrShadowHostElement()->renderStyle() != parent->renderStyle())
        return false;
    if (candidate.tagQName() != element().tagQName())
        return false;
    if (candidate.inlineStyle())
        return false;
    if (candidate.needsStyleRecalc())
        return false;
    if (candidate.isSVGElement() && toSVGElement(candidate).animatedSMILStyleProperties())
        return false;
    if (candidate.isLink() != element().isLink())
        return false;
    if (candidate.shadowPseudoId() != element().shadowPseudoId())
        return false;
    if (!sharingCandidateHasIdenticalStyleAffectingAttributes(candidate))
        return false;
    if (candidate.additionalPresentationAttributeStyle() != element().additionalPresentationAttributeStyle())
        return false;
    if (candidate.hasID() && m_features.hasSelectorForId(candidate.idForStyleResolution()))
        return false;
    if (candidate.hasScopedHTMLStyleChild())
        return false;
    if (candidate.shadow() && candidate.shadow()->containsActiveStyles() && !sharingCandidateShadowHasSharedStyleSheetContents(candidate))
        return false;
    if (!sharingCandidateDistributedToSameInsertionPoint(candidate))
        return false;
    if (candidate.isInTopLayer() != element().isInTopLayer())
        return false;

    bool isControl = candidate.isFormControlElement();

    if (isControl != element().isFormControlElement())
        return false;

    if (isControl && !canShareStyleWithControl(candidate))
        return false;

    // FIXME: This line is surprisingly hot, we may wish to inline hasDirectionAuto into StyleResolver.
    if (candidate.isHTMLElement() && toHTMLElement(candidate).hasDirectionAuto())
        return false;

    if (candidate.isLink() && m_context.elementLinkState() != style->insideLink())
        return false;

    if (candidate.isUnresolvedCustomElement() != element().isUnresolvedCustomElement())
        return false;

    if (element().parentOrShadowHostElement() != parent) {
        if (!parent->isStyledElement())
            return false;
        if (parent->hasScopedHTMLStyleChild())
            return false;
        if (parent->inlineStyle())
            return false;
        if (parent->isSVGElement() && toSVGElement(parent)->animatedSMILStyleProperties())
            return false;
        if (parent->hasID() && m_features.hasSelectorForId(parent->idForStyleResolution()))
            return false;
        if (!parent->childrenSupportStyleSharing())
            return false;
    }

    return true;
}

bool SharedStyleFinder::documentContainsValidCandidate() const
{
    for (Element* element = document().documentElement(); element; element = ElementTraversal::next(*element)) {
        if (element->supportsStyleSharing() && canShareStyleWithElement(*element))
            return true;
    }
    return false;
}

inline Element* SharedStyleFinder::findElementForStyleSharing() const
{
    StyleSharingList& styleSharingList = m_styleResolver.styleSharingList();
    for (StyleSharingList::iterator it = styleSharingList.begin(); it != styleSharingList.end(); ++it) {
        Element& candidate = **it;
        if (!canShareStyleWithElement(candidate))
            continue;
        if (it != styleSharingList.begin()) {
            // Move the element to the front of the LRU
            styleSharingList.remove(it);
            styleSharingList.prepend(&candidate);
        }
        return &candidate;
    }
    m_styleResolver.addToStyleSharingList(element());
    return 0;
}

bool SharedStyleFinder::matchesRuleSet(RuleSet* ruleSet)
{
    if (!ruleSet)
        return false;
    ElementRuleCollector collector(m_context, m_styleResolver.selectorFilter());
    return collector.hasAnyMatchingRules(ruleSet);
}

RenderStyle* SharedStyleFinder::findSharedStyle()
{
    INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleLookups);

    if (!element().supportsStyleSharing())
        return 0;

    // Cache whether context.element() is affected by any known class selectors.
    m_elementAffectedByClassRules = element().hasClass() && classNamesAffectedByRules(element().classNames());

    Element* shareElement = findElementForStyleSharing();

    if (!shareElement) {
        if (m_styleResolver.stats() && m_styleResolver.stats()->printMissedCandidateCount && documentContainsValidCandidate())
            INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleMissed);
        return 0;
    }

    INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleFound);

    if (matchesRuleSet(m_siblingRuleSet)) {
        INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleRejectedBySiblingRules);
        return 0;
    }

    if (matchesRuleSet(m_uncommonAttributeRuleSet)) {
        INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleRejectedByUncommonAttributeRules);
        return 0;
    }

    // Tracking child index requires unique style for each node. This may get set by the sibling rule match above.
    if (!element().parentElementOrShadowRoot()->childrenSupportStyleSharing()) {
        INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleRejectedByParent);
        return 0;
    }

    return shareElement->renderStyle();
}

}
<|endoftext|>


<commit_before>//===- PPC64.cpp ----------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Support/Endian.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;

static uint64_t PPC64TocOffset = 0x8000;

uint64_t elf::getPPC64TocBase() {
  // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
  // TOC starts where the first of these sections starts. We always create a
  // .got when we see a relocation that uses it, so for us the start is always
  // the .got.
  uint64_t TocVA = InX::Got->getVA();

  // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
  // thus permitting a full 64 Kbytes segment. Note that the glibc startup
  // code (crt1.o) assumes that you can get from the TOC base to the
  // start of the .toc section with only a single (signed) 16-bit relocation.
  return TocVA + PPC64TocOffset;
}

namespace {
class PPC64 final : public TargetInfo {
public:
  PPC64();
  uint32_t calcEFlags() const override;
  RelExpr getRelExpr(RelType Type, const Symbol &S,
                     const uint8_t *Loc) const override;
  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
                int32_t Index, unsigned RelOff) const override;
  void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
  void writeGotHeader(uint8_t *Buf) const override;
};
} // namespace

// Relocation masks following the #lo(value), #hi(value), #ha(value),
// #higher(value), #highera(value), #highest(value), and #highesta(value)
// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
// document.
static uint16_t applyPPCLo(uint64_t V) { return V; }
static uint16_t applyPPCHi(uint64_t V) { return V >> 16; }
static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; }
static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; }
static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; }
static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; }
static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }

PPC64::PPC64() {
  GotRel = R_PPC64_GLOB_DAT;
  RelativeRel = R_PPC64_RELATIVE;
  GotEntrySize = 8;
  GotPltEntrySize = 8;
  PltEntrySize = 32;
  PltHeaderSize = 0;
  GotBaseSymInGotPlt = false;
  GotBaseSymOff = 0x8000;

  GotHeaderEntriesNum = 1;
  GotPltHeaderEntriesNum = 2;
  PltRel = R_PPC64_JMP_SLOT;

  // We need 64K pages (at least under glibc/Linux, the loader won't
  // set different permissions on a finer granularity than that).
  DefaultMaxPageSize = 65536;

  // The PPC64 ELF ABI v1 spec, says:
  //
  //   It is normally desirable to put segments with different characteristics
  //   in separate 256 Mbyte portions of the address space, to give the
  //   operating system full paging flexibility in the 64-bit address space.
  //
  // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
  // use 0x10000000 as the starting address.
  DefaultImageBase = 0x10000000;

  TrapInstr =
      (Config->IsLE == sys::IsLittleEndianHost) ? 0x7fe00008 : 0x0800e07f;
}

static uint32_t getEFlags(InputFile *File) {
  // Get the e_flag from the input file and issue an error if incompatible
  // e_flag encountered.

  uint32_t EFlags = Config->IsLE ?
    cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags :
    cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags;
  if (EFlags > 2) {
    error("incompatible e_flags: " +  toString(File));
    return 0;
  }
  return EFlags;
}

uint32_t PPC64::calcEFlags() const {
  assert(!ObjectFiles.empty());

  uint32_t NonZeroFlag;
  for (InputFile *F : makeArrayRef(ObjectFiles)) {
    NonZeroFlag = getEFlags(F);
    if (NonZeroFlag)
      break;
  }

  // Verify that all input files have either the same e_flags, or zero.
  for (InputFile *F : makeArrayRef(ObjectFiles)) {
    uint32_t Flag = getEFlags(F);
    if (Flag == 0 || Flag == NonZeroFlag)
      continue;
    error(toString(F) + ": ABI version " + Twine(Flag) +
          " is not compatible with ABI version " + Twine(NonZeroFlag) +
          " output");
    return 0;
  }

  if (NonZeroFlag == 1) {
    error("PPC64 V1 ABI not supported");
    return 0;
  }

  return 2;
}

RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
                          const uint8_t *Loc) const {
  switch (Type) {
  case R_PPC64_TOC16:
  case R_PPC64_TOC16_DS:
  case R_PPC64_TOC16_HA:
  case R_PPC64_TOC16_HI:
  case R_PPC64_TOC16_LO:
  case R_PPC64_TOC16_LO_DS:
    return R_GOTREL;
  case R_PPC64_TOC:
    return R_PPC_TOC;
  case R_PPC64_REL24:
    return R_PPC_CALL_PLT;
  case R_PPC64_REL16_LO:
  case R_PPC64_REL16_HA:
    return R_PC;
  default:
    return R_ABS;
  }
}

void PPC64::writeGotHeader(uint8_t *Buf) const {
  write64(Buf, getPPC64TocBase());
}

void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
                     uint64_t PltEntryAddr, int32_t Index,
                     unsigned RelOff) const {
  uint64_t Off = GotPltEntryAddr - getPPC64TocBase();

  // The most-common form of the plt stub. This assumes that the toc-pointer
  // register is properly initalized, and that the stub must save the toc
  // pointer value to the stack-save slot reserved for it (sp + 24).
  // There are 2 other variants but we don't have to emit those until we add
  // support for R_PPC64_REL24_NOTOC and R_PPC64_TOCSAVE relocations.
  // We are missing a super simple optimization, where if the upper 16 bits of
  // the offset are zero, then we can omit the addis instruction, and load
  // r2 + lo-offset directly into r12. I decided to leave this out in the
  // spirit of keeping it simple until we can link actual non-trivial
  // programs.
  write32(Buf +  0, 0xf8410018);                    // std     r2,24(r1)
  write32(Buf +  4, 0x3d820000 | applyPPCHa(Off));  // addis   r12,r2, X@plt@to@ha
  write32(Buf +  8, 0xe98c0000 | applyPPCLo(Off));  // ld      r12,X@plt@toc@l(r12)
  write32(Buf + 12, 0x7d8903a6);                    // mtctr    r12
  write32(Buf + 16, 0x4e800420);                    // bctr
}

static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
  uint64_t V = Val - PPC64TocOffset;
  switch (Type) {
  case R_PPC64_TOC16:
    return {R_PPC64_ADDR16, V};
  case R_PPC64_TOC16_DS:
    return {R_PPC64_ADDR16_DS, V};
  case R_PPC64_TOC16_HA:
    return {R_PPC64_ADDR16_HA, V};
  case R_PPC64_TOC16_HI:
    return {R_PPC64_ADDR16_HI, V};
  case R_PPC64_TOC16_LO:
    return {R_PPC64_ADDR16_LO, V};
  case R_PPC64_TOC16_LO_DS:
    return {R_PPC64_ADDR16_LO_DS, V};
  default:
    return {Type, Val};
  }
}

void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
  // For a TOC-relative relocation, proceed in terms of the corresponding
  // ADDR16 relocation type.
  std::tie(Type, Val) = toAddr16Rel(Type, Val);

  switch (Type) {
  case R_PPC64_ADDR14: {
    checkAlignment(Loc, Val, 4, Type);
    // Preserve the AA/LK bits in the branch instruction
    uint8_t AALK = Loc[3];
    write16(Loc + 2, (AALK & 3) | (Val & 0xfffc));
    break;
  }
  case R_PPC64_ADDR16:
    checkInt(Loc, Val, 16, Type);
    write16(Loc, Val);
    break;
  case R_PPC64_ADDR16_DS:
    checkInt(Loc, Val, 16, Type);
    write16(Loc, (read16(Loc) & 3) | (Val & ~3));
    break;
  case R_PPC64_ADDR16_HA:
  case R_PPC64_REL16_HA:
    write16(Loc, applyPPCHa(Val));
    break;
  case R_PPC64_ADDR16_HI:
  case R_PPC64_REL16_HI:
    write16(Loc, applyPPCHi(Val));
    break;
  case R_PPC64_ADDR16_HIGHER:
    write16(Loc, applyPPCHigher(Val));
    break;
  case R_PPC64_ADDR16_HIGHERA:
    write16(Loc, applyPPCHighera(Val));
    break;
  case R_PPC64_ADDR16_HIGHEST:
    write16(Loc, applyPPCHighest(Val));
    break;
  case R_PPC64_ADDR16_HIGHESTA:
    write16(Loc, applyPPCHighesta(Val));
    break;
  case R_PPC64_ADDR16_LO:
  case R_PPC64_REL16_LO:
    write16(Loc, applyPPCLo(Val));
    break;
  case R_PPC64_ADDR16_LO_DS:
    write16(Loc, (read16(Loc) & 3) | (applyPPCLo(Val) & ~3));
    break;
  case R_PPC64_ADDR32:
  case R_PPC64_REL32:
    checkInt(Loc, Val, 32, Type);
    write32(Loc, Val);
    break;
  case R_PPC64_ADDR64:
  case R_PPC64_REL64:
  case R_PPC64_TOC:
    write64(Loc, Val);
    break;
  case R_PPC64_REL24: {
    uint32_t Mask = 0x03FFFFFC;
    checkInt(Loc, Val, 24, Type);
    write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
    break;
  }
  default:
    error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
  }
}

TargetInfo *elf::getPPC64TargetInfo() {
  static PPC64 Target;
  return &Target;
}
<commit_msg>[PPC64] Remove support for ELF V1 ABI in LLD - buildbot fix<commit_after>//===- PPC64.cpp ----------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Support/Endian.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;

static uint64_t PPC64TocOffset = 0x8000;

uint64_t elf::getPPC64TocBase() {
  // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
  // TOC starts where the first of these sections starts. We always create a
  // .got when we see a relocation that uses it, so for us the start is always
  // the .got.
  uint64_t TocVA = InX::Got->getVA();

  // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
  // thus permitting a full 64 Kbytes segment. Note that the glibc startup
  // code (crt1.o) assumes that you can get from the TOC base to the
  // start of the .toc section with only a single (signed) 16-bit relocation.
  return TocVA + PPC64TocOffset;
}

namespace {
class PPC64 final : public TargetInfo {
public:
  PPC64();
  uint32_t calcEFlags() const override;
  RelExpr getRelExpr(RelType Type, const Symbol &S,
                     const uint8_t *Loc) const override;
  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
                int32_t Index, unsigned RelOff) const override;
  void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
  void writeGotHeader(uint8_t *Buf) const override;
};
} // namespace

// Relocation masks following the #lo(value), #hi(value), #ha(value),
// #higher(value), #highera(value), #highest(value), and #highesta(value)
// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
// document.
static uint16_t applyPPCLo(uint64_t V) { return V; }
static uint16_t applyPPCHi(uint64_t V) { return V >> 16; }
static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; }
static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; }
static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; }
static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; }
static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }

PPC64::PPC64() {
  GotRel = R_PPC64_GLOB_DAT;
  RelativeRel = R_PPC64_RELATIVE;
  GotEntrySize = 8;
  GotPltEntrySize = 8;
  PltEntrySize = 32;
  PltHeaderSize = 0;
  GotBaseSymInGotPlt = false;
  GotBaseSymOff = 0x8000;

  GotHeaderEntriesNum = 1;
  GotPltHeaderEntriesNum = 2;
  PltRel = R_PPC64_JMP_SLOT;

  // We need 64K pages (at least under glibc/Linux, the loader won't
  // set different permissions on a finer granularity than that).
  DefaultMaxPageSize = 65536;

  // The PPC64 ELF ABI v1 spec, says:
  //
  //   It is normally desirable to put segments with different characteristics
  //   in separate 256 Mbyte portions of the address space, to give the
  //   operating system full paging flexibility in the 64-bit address space.
  //
  // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
  // use 0x10000000 as the starting address.
  DefaultImageBase = 0x10000000;

  TrapInstr =
      (Config->IsLE == sys::IsLittleEndianHost) ? 0x7fe00008 : 0x0800e07f;
}

static uint32_t getEFlags(InputFile *File) {
  // Get the e_flag from the input file and issue an error if incompatible
  // e_flag encountered.
  uint32_t EFlags;
  switch (Config->EKind) {
  case ELF64BEKind:
    EFlags = cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags;
    break;
  case ELF64LEKind:
    EFlags = cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags;
    break;
  default:
    llvm_unreachable("unknown Config->EKind");
  }
  if (EFlags > 2) {
    error("incompatible e_flags: " +  toString(File));
    return 0;
  }
  return EFlags;
}

uint32_t PPC64::calcEFlags() const {
  assert(!ObjectFiles.empty());

  uint32_t NonZeroFlag;
  for (InputFile *F : makeArrayRef(ObjectFiles)) {
    NonZeroFlag = getEFlags(F);
    if (NonZeroFlag)
      break;
  }

  // Verify that all input files have either the same e_flags, or zero.
  for (InputFile *F : makeArrayRef(ObjectFiles)) {
    uint32_t Flag = getEFlags(F);
    if (Flag == 0 || Flag == NonZeroFlag)
      continue;
    error(toString(F) + ": ABI version " + Twine(Flag) +
          " is not compatible with ABI version " + Twine(NonZeroFlag) +
          " output");
    return 0;
  }

  if (NonZeroFlag == 1) {
    error("PPC64 V1 ABI not supported");
    return 0;
  }

  return 2;
}

RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
                          const uint8_t *Loc) const {
  switch (Type) {
  case R_PPC64_TOC16:
  case R_PPC64_TOC16_DS:
  case R_PPC64_TOC16_HA:
  case R_PPC64_TOC16_HI:
  case R_PPC64_TOC16_LO:
  case R_PPC64_TOC16_LO_DS:
    return R_GOTREL;
  case R_PPC64_TOC:
    return R_PPC_TOC;
  case R_PPC64_REL24:
    return R_PPC_CALL_PLT;
  case R_PPC64_REL16_LO:
  case R_PPC64_REL16_HA:
    return R_PC;
  default:
    return R_ABS;
  }
}

void PPC64::writeGotHeader(uint8_t *Buf) const {
  write64(Buf, getPPC64TocBase());
}

void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
                     uint64_t PltEntryAddr, int32_t Index,
                     unsigned RelOff) const {
  uint64_t Off = GotPltEntryAddr - getPPC64TocBase();

  // The most-common form of the plt stub. This assumes that the toc-pointer
  // register is properly initalized, and that the stub must save the toc
  // pointer value to the stack-save slot reserved for it (sp + 24).
  // There are 2 other variants but we don't have to emit those until we add
  // support for R_PPC64_REL24_NOTOC and R_PPC64_TOCSAVE relocations.
  // We are missing a super simple optimization, where if the upper 16 bits of
  // the offset are zero, then we can omit the addis instruction, and load
  // r2 + lo-offset directly into r12. I decided to leave this out in the
  // spirit of keeping it simple until we can link actual non-trivial
  // programs.
  write32(Buf +  0, 0xf8410018);                    // std     r2,24(r1)
  write32(Buf +  4, 0x3d820000 | applyPPCHa(Off));  // addis   r12,r2, X@plt@to@ha
  write32(Buf +  8, 0xe98c0000 | applyPPCLo(Off));  // ld      r12,X@plt@toc@l(r12)
  write32(Buf + 12, 0x7d8903a6);                    // mtctr    r12
  write32(Buf + 16, 0x4e800420);                    // bctr
}

static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
  uint64_t V = Val - PPC64TocOffset;
  switch (Type) {
  case R_PPC64_TOC16:
    return {R_PPC64_ADDR16, V};
  case R_PPC64_TOC16_DS:
    return {R_PPC64_ADDR16_DS, V};
  case R_PPC64_TOC16_HA:
    return {R_PPC64_ADDR16_HA, V};
  case R_PPC64_TOC16_HI:
    return {R_PPC64_ADDR16_HI, V};
  case R_PPC64_TOC16_LO:
    return {R_PPC64_ADDR16_LO, V};
  case R_PPC64_TOC16_LO_DS:
    return {R_PPC64_ADDR16_LO_DS, V};
  default:
    return {Type, Val};
  }
}

void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
  // For a TOC-relative relocation, proceed in terms of the corresponding
  // ADDR16 relocation type.
  std::tie(Type, Val) = toAddr16Rel(Type, Val);

  switch (Type) {
  case R_PPC64_ADDR14: {
    checkAlignment(Loc, Val, 4, Type);
    // Preserve the AA/LK bits in the branch instruction
    uint8_t AALK = Loc[3];
    write16(Loc + 2, (AALK & 3) | (Val & 0xfffc));
    break;
  }
  case R_PPC64_ADDR16:
    checkInt(Loc, Val, 16, Type);
    write16(Loc, Val);
    break;
  case R_PPC64_ADDR16_DS:
    checkInt(Loc, Val, 16, Type);
    write16(Loc, (read16(Loc) & 3) | (Val & ~3));
    break;
  case R_PPC64_ADDR16_HA:
  case R_PPC64_REL16_HA:
    write16(Loc, applyPPCHa(Val));
    break;
  case R_PPC64_ADDR16_HI:
  case R_PPC64_REL16_HI:
    write16(Loc, applyPPCHi(Val));
    break;
  case R_PPC64_ADDR16_HIGHER:
    write16(Loc, applyPPCHigher(Val));
    break;
  case R_PPC64_ADDR16_HIGHERA:
    write16(Loc, applyPPCHighera(Val));
    break;
  case R_PPC64_ADDR16_HIGHEST:
    write16(Loc, applyPPCHighest(Val));
    break;
  case R_PPC64_ADDR16_HIGHESTA:
    write16(Loc, applyPPCHighesta(Val));
    break;
  case R_PPC64_ADDR16_LO:
  case R_PPC64_REL16_LO:
    write16(Loc, applyPPCLo(Val));
    break;
  case R_PPC64_ADDR16_LO_DS:
    write16(Loc, (read16(Loc) & 3) | (applyPPCLo(Val) & ~3));
    break;
  case R_PPC64_ADDR32:
  case R_PPC64_REL32:
    checkInt(Loc, Val, 32, Type);
    write32(Loc, Val);
    break;
  case R_PPC64_ADDR64:
  case R_PPC64_REL64:
  case R_PPC64_TOC:
    write64(Loc, Val);
    break;
  case R_PPC64_REL24: {
    uint32_t Mask = 0x03FFFFFC;
    checkInt(Loc, Val, 24, Type);
    write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
    break;
  }
  default:
    error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
  }
}

TargetInfo *elf::getPPC64TargetInfo() {
  static PPC64 Target;
  return &Target;
}
<|endoftext|>


<commit_before>/* FREEVERB - a reverberator

   This reverb instrument is based on Freeverb, by Jezar
   (http://www.dreampoint.co.uk/~jzracc/freeverb.htm).

   p0  = output start time
   p1  = input start time
   p2  = input duration
   p3  = amplitude multiplier
   p4  = room size (0-1.07143 ... don't ask)
   p5  = pre-delay time (time between dry signal and onset of reverb)
   p6  = ring-down duration
   p7  = damp (0-100%)
   p8  = dry signal level (0-100%)
   p9  = wet signal level (0-100%)
   p10 = stereo width of reverb (0-100%)

   Assumes function table 1 is amplitude curve for the note. (Try gen 18.)
   Or you can just call setline. If no setline or function table 1, uses
   flat amplitude curve.  The curve is applied to the input sound *before*
   it enters the reverberator.

   If you enter a room size greater than the maximum, you'll get the
   maximum amount -- which is probably an infinite reverb time.

   Input can be mono or stereo; output can be mono or stereo.

   Be careful with the dry and wet levels -- it's easy to get extreme
   clipping!

   John Gibson <johngibson@virginia.edu>, 2 Feb 2001
*/
#include <stdio.h>
#include <stdlib.h>
#include <ugens.h>
#include <math.h>
#include <mixerr.h>
#include <Instrument.h>
#include "FREEVERB.h"
#include <rt.h>
#include <rtdefs.h>

FREEVERB :: FREEVERB() : Instrument()
{
   in = NULL;
   branch = 0;
}

FREEVERB :: ~FREEVERB()
{
   delete [] in;
   delete rvb;
}

int FREEVERB :: init(float p[], int n_args)
{
   float outskip, inskip, dur, roomsize, damp, dry, wet, width, max_roomsize;
   float predelay_time;
   int   predelay_samps;

   outskip = p[0];
   inskip = p[1];
   dur = p[2];
   amp = p[3];
   roomsize = p[4];
   predelay_time = p[5];
   ringdur = p[6];
   damp = p[7];
   dry = p[8];
   wet = p[9];
   width = p[10];

   /* Keep reverb comb feedback <= 1.0 */
   max_roomsize = (1.0 - offsetroom) / scaleroom;
   if (roomsize < 0.0)
      die("FREEVERB", "Room size must be between 0 and %g.", max_roomsize);
   if (roomsize > max_roomsize) {
      roomsize = max_roomsize;
      advise("FREEVERB", "Room size cannot be greater than %g. Adjusting...",
             max_roomsize);
   }
   predelay_samps = (int)((predelay_time * SR) + 0.5);
   if (predelay_samps > max_predelay_samps)
      die("FREEVERB", "Pre-delay must be between 0 and %g seconds.",
                                             (float) max_predelay_samps / SR);
   if (damp < 0.0 || damp > 100.0)
      die("FREEVERB", "Damp must be between 0 and 100%%.");
   if (dry < 0.0 || dry > 100.0)
      die("FREEVERB", "Dry signal level must be between 0 and 100%%.");
   if (wet < 0.0 || wet > 100.0)
      die("FREEVERB", "Wet signal level must be between 0 and 100%%.");
   if (width < 0.0 || width > 100.0)
      die("FREEVERB", "Width must be between 0 and 100%%.");

   rtsetinput(inskip, this);
   nsamps = rtsetoutput(outskip, dur + ringdur, this);
   insamps = (int)(dur * SR);

   /* Legal channel configs:  1in1out, 2in2out, 1in2out */
   if (inputchans > 2)
      die("FREEVERB", "Can't have more than 2 input channels.");
   if (outputchans > 2)
      die("FREEVERB", "Can't have more than 2 output channels.");

   rvb = new revmodel();

   rvb->setroomsize(roomsize);
   rvb->setpredelay(predelay_samps);
   rvb->setdamp(damp * 0.01);
   rvb->setdry(dry * 0.01);
   rvb->setwet(wet * 0.01);
   rvb->setwidth(width * 0.01);

   amparray = floc(1);
   if (amparray) {
      int lenamp = fsize(1);
      tableset(dur, lenamp, amptabs);
   }
   else
      advise("FREEVERB", "Setting phrase curve to all 1's.");

   aamp = amp;                  /* in case amparray == NULL */

   skip = (int) (SR / (float) resetval);

   return nsamps;
}

int FREEVERB :: run()
{
   int   samps;
   float *inL, *inR, *outL, *outR;

   if (in == NULL)
      in = new float [RTBUFSAMPS * inputchans];

   Instrument :: run();

   inL = in;
   inR = inputchans > 1 ? in + 1 : in;
   outL = outbuf;
   outR = outputchans > 1 ? outbuf + 1 : outbuf;

   samps = chunksamps * inputchans;

   if (cursamp < insamps)
      rtgetin(in, this, samps);

   /* Scale input signal by amplitude multiplier and setline curve. */
   for (int i = 0; i < samps; i += inputchans) {
      if (cursamp < insamps) {           /* still taking input from file */
         if (--branch < 0) {
            if (amparray)
               aamp = tablei(cursamp, amparray, amptabs) * amp;
            branch = skip;
         }
         in[i] *= aamp;
         if (inputchans == 2)
            in[i + 1] *= aamp;
      }
      else {                             /* in ringdown phase */
         in[i] = 0.0;
         if (inputchans == 2)
            in[i + 1] = 0.0;
      }
      cursamp++;
   }

   /* Hand off to Freeverb to do the actual work. */
   rvb->processreplace(inL, inR, outL, outR, chunksamps, inputchans,
                                                         outputchans);

   return chunksamps;
}

Instrument *makeFREEVERB()
{
   FREEVERB *inst;

   inst = new FREEVERB();
   inst->set_bus_config("FREEVERB");

   return inst;
}

void rtprofile()
{
   RT_INTRO("FREEVERB", makeFREEVERB);
}

<commit_msg>Removed misleading comment about legal channel configs.<commit_after>/* FREEVERB - a reverberator

   This reverb instrument is based on Freeverb, by Jezar
   (http://www.dreampoint.co.uk/~jzracc/freeverb.htm).

   p0  = output start time
   p1  = input start time
   p2  = input duration
   p3  = amplitude multiplier
   p4  = room size (0-1.07143 ... don't ask)
   p5  = pre-delay time (time between dry signal and onset of reverb)
   p6  = ring-down duration
   p7  = damp (0-100%)
   p8  = dry signal level (0-100%)
   p9  = wet signal level (0-100%)
   p10 = stereo width of reverb (0-100%)

   Assumes function table 1 is amplitude curve for the note. (Try gen 18.)
   Or you can just call setline. If no setline or function table 1, uses
   flat amplitude curve.  The curve is applied to the input sound *before*
   it enters the reverberator.

   If you enter a room size greater than the maximum, you'll get the
   maximum amount -- which is probably an infinite reverb time.

   Input can be mono or stereo; output can be mono or stereo.

   Be careful with the dry and wet levels -- it's easy to get extreme
   clipping!

   John Gibson <johngibson@virginia.edu>, 2 Feb 2001
*/
#include <stdio.h>
#include <stdlib.h>
#include <ugens.h>
#include <math.h>
#include <mixerr.h>
#include <Instrument.h>
#include "FREEVERB.h"
#include <rt.h>
#include <rtdefs.h>

FREEVERB :: FREEVERB() : Instrument()
{
   in = NULL;
   branch = 0;
}

FREEVERB :: ~FREEVERB()
{
   delete [] in;
   delete rvb;
}

int FREEVERB :: init(float p[], int n_args)
{
   float outskip, inskip, dur, roomsize, damp, dry, wet, width, max_roomsize;
   float predelay_time;
   int   predelay_samps;

   outskip = p[0];
   inskip = p[1];
   dur = p[2];
   amp = p[3];
   roomsize = p[4];
   predelay_time = p[5];
   ringdur = p[6];
   damp = p[7];
   dry = p[8];
   wet = p[9];
   width = p[10];

   /* Keep reverb comb feedback <= 1.0 */
   max_roomsize = (1.0 - offsetroom) / scaleroom;
   if (roomsize < 0.0)
      die("FREEVERB", "Room size must be between 0 and %g.", max_roomsize);
   if (roomsize > max_roomsize) {
      roomsize = max_roomsize;
      advise("FREEVERB", "Room size cannot be greater than %g. Adjusting...",
             max_roomsize);
   }
   predelay_samps = (int)((predelay_time * SR) + 0.5);
   if (predelay_samps > max_predelay_samps)
      die("FREEVERB", "Pre-delay must be between 0 and %g seconds.",
                                             (float) max_predelay_samps / SR);
   if (damp < 0.0 || damp > 100.0)
      die("FREEVERB", "Damp must be between 0 and 100%%.");
   if (dry < 0.0 || dry > 100.0)
      die("FREEVERB", "Dry signal level must be between 0 and 100%%.");
   if (wet < 0.0 || wet > 100.0)
      die("FREEVERB", "Wet signal level must be between 0 and 100%%.");
   if (width < 0.0 || width > 100.0)
      die("FREEVERB", "Width must be between 0 and 100%%.");

   rtsetinput(inskip, this);
   nsamps = rtsetoutput(outskip, dur + ringdur, this);
   insamps = (int)(dur * SR);

   if (inputchans > 2)
      die("FREEVERB", "Can't have more than 2 input channels.");
   if (outputchans > 2)
      die("FREEVERB", "Can't have more than 2 output channels.");

   rvb = new revmodel();

   rvb->setroomsize(roomsize);
   rvb->setpredelay(predelay_samps);
   rvb->setdamp(damp * 0.01);
   rvb->setdry(dry * 0.01);
   rvb->setwet(wet * 0.01);
   rvb->setwidth(width * 0.01);

   amparray = floc(1);
   if (amparray) {
      int lenamp = fsize(1);
      tableset(dur, lenamp, amptabs);
   }
   else
      advise("FREEVERB", "Setting phrase curve to all 1's.");

   aamp = amp;                  /* in case amparray == NULL */

   skip = (int) (SR / (float) resetval);

   return nsamps;
}

int FREEVERB :: run()
{
   int   samps;
   float *inL, *inR, *outL, *outR;

   if (in == NULL)
      in = new float [RTBUFSAMPS * inputchans];

   Instrument :: run();

   inL = in;
   inR = inputchans > 1 ? in + 1 : in;
   outL = outbuf;
   outR = outputchans > 1 ? outbuf + 1 : outbuf;

   samps = chunksamps * inputchans;

   if (cursamp < insamps)
      rtgetin(in, this, samps);

   /* Scale input signal by amplitude multiplier and setline curve. */
   for (int i = 0; i < samps; i += inputchans) {
      if (cursamp < insamps) {           /* still taking input from file */
         if (--branch < 0) {
            if (amparray)
               aamp = tablei(cursamp, amparray, amptabs) * amp;
            branch = skip;
         }
         in[i] *= aamp;
         if (inputchans == 2)
            in[i + 1] *= aamp;
      }
      else {                             /* in ringdown phase */
         in[i] = 0.0;
         if (inputchans == 2)
            in[i + 1] = 0.0;
      }
      cursamp++;
   }

   /* Hand off to Freeverb to do the actual work. */
   rvb->processreplace(inL, inR, outL, outR, chunksamps, inputchans,
                                                         outputchans);

   return chunksamps;
}

Instrument *makeFREEVERB()
{
   FREEVERB *inst;

   inst = new FREEVERB();
   inst->set_bus_config("FREEVERB");

   return inst;
}

void rtprofile()
{
   RT_INTRO("FREEVERB", makeFREEVERB);
}

<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "platform/graphics/StaticBitmapImage.h"

#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/ImageObserver.h"
#include "platform/graphics/skia/NativeImageSkia.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkShader.h"

namespace blink {

PassRefPtr<Image> StaticBitmapImage::create(PassRefPtr<SkImage> image)
{
    return adoptRef(new StaticBitmapImage(image));
}

StaticBitmapImage::StaticBitmapImage(PassRefPtr<SkImage> image) : m_image(image)
{
}

StaticBitmapImage::~StaticBitmapImage() { }

IntSize StaticBitmapImage::size() const
{
    return IntSize(m_image->width(), m_image->height());
}

bool StaticBitmapImage::currentFrameKnownToBeOpaque()
{
    return m_image->isOpaque();
}

void StaticBitmapImage::draw(GraphicsContext* ctx, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, blink::WebBlendMode blendMode)
{
    FloatRect normDstRect = adjustForNegativeSize(dstRect);
    FloatRect normSrcRect = adjustForNegativeSize(srcRect);

    normSrcRect.intersect(FloatRect(0, 0, m_image->width(), m_image->height()));

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return; // Nothing to draw.

    ASSERT(normSrcRect.width() <= m_image->width() && normSrcRect.height() <= m_image->height());

    SkPaint paint;
    ctx->preparePaintForDrawRectToRect(&paint, srcRect, dstRect, compositeOp, blendMode);

    SkRect srcSkRect = WebCoreFloatRectToSKRect(normSrcRect);
    SkRect dstSkRect = WebCoreFloatRectToSKRect(normDstRect);

    SkCanvas* canvas = ctx->canvas();

    canvas->drawImageRect(m_image.get(), &srcSkRect, dstSkRect, &paint);

    if (ImageObserver* observer = imageObserver())
        observer->didDraw(this);
}

}
<commit_msg>Added a non-null check in the constructor of StaticBitmapImage<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "platform/graphics/StaticBitmapImage.h"

#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/ImageObserver.h"
#include "platform/graphics/skia/NativeImageSkia.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkShader.h"

namespace blink {

PassRefPtr<Image> StaticBitmapImage::create(PassRefPtr<SkImage> image)
{
    return adoptRef(new StaticBitmapImage(image));
}

StaticBitmapImage::StaticBitmapImage(PassRefPtr<SkImage> image) : m_image(image)
{
    ASSERT(m_image);
}

StaticBitmapImage::~StaticBitmapImage() { }

IntSize StaticBitmapImage::size() const
{
    return IntSize(m_image->width(), m_image->height());
}

bool StaticBitmapImage::currentFrameKnownToBeOpaque()
{
    return m_image->isOpaque();
}

void StaticBitmapImage::draw(GraphicsContext* ctx, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, blink::WebBlendMode blendMode)
{
    FloatRect normDstRect = adjustForNegativeSize(dstRect);
    FloatRect normSrcRect = adjustForNegativeSize(srcRect);

    normSrcRect.intersect(FloatRect(0, 0, m_image->width(), m_image->height()));

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return; // Nothing to draw.

    ASSERT(normSrcRect.width() <= m_image->width() && normSrcRect.height() <= m_image->height());

    SkPaint paint;
    ctx->preparePaintForDrawRectToRect(&paint, srcRect, dstRect, compositeOp, blendMode);

    SkRect srcSkRect = WebCoreFloatRectToSKRect(normSrcRect);
    SkRect dstSkRect = WebCoreFloatRectToSKRect(normDstRect);

    SkCanvas* canvas = ctx->canvas();

    canvas->drawImageRect(m_image.get(), &srcSkRect, dstSkRect, &paint);

    if (ImageObserver* observer = imageObserver())
        observer->didDraw(this);
}

}
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <memory>

#include "buffer.hpp"
#include "malloc_utils.hpp"

namespace ftcxx {

    const size_t Buffer::INITIAL_CAPACITY = 1<<10;
    const size_t Buffer::MAXIMUM_CAPACITY = 1<<18;
    const double Buffer::FULLNESS_RATIO = 0.9;

    void Buffer::init() {
        _buf.reset(std::malloc(_capacity));
    }

    /**
     * Implements our growth strategy.  Currently we double until we get
     * up to 4kB so that we can quickly reach the point where jemalloc can
     * help us resize in-place, but after that point we grow by a factor
     * of 1.5x.
     *
     * FBVector doubles once it is bigger than 128kB, but I don't think we
     * actually want to because that's about when we want to stop growing.
     */
    size_t Buffer::next_alloc_size(size_t sz) {
        if (sz < malloc_utils::jemallocMinInPlaceExpandable) {
            return sz * 2;
        }
#if 0
        else if (sz > (128<<10)) {
            return sz * 2;
        }
#endif
        else {
            return (sz * 3 + 1) / 2;
        }
    }

    void Buffer::grow(size_t sz) {
        size_t new_capacity = _capacity;
        while (new_capacity < _end + sz) {
            new_capacity = next_alloc_size(new_capacity);
        }
        new_capacity = malloc_utils::goodMallocSize(new_capacity);
        assert(new_capacity >= _capacity);  // overflow?
        if (new_capacity > _capacity) {
            // This section isn't exception-safe, but smartRealloc already
            // isn't.  The only thing we can throw in here is
            // std::bad_alloc, in which case we're kind of screwed anyway.
            _buf.reset(malloc_utils::smartRealloc(_buf.release(), new_capacity, 0, 0, _capacity));
        }
    }

} // namespace ftcxx
<commit_msg>moved minor calculation<commit_after>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <memory>

#include "buffer.hpp"
#include "malloc_utils.hpp"

namespace ftcxx {

    const size_t Buffer::INITIAL_CAPACITY = 1<<10;
    const size_t Buffer::MAXIMUM_CAPACITY = 1<<18;
    const double Buffer::FULLNESS_RATIO = 0.9;

    void Buffer::init() {
        _buf.reset(std::malloc(_capacity));
    }

    /**
     * Implements our growth strategy.  Currently we double until we get
     * up to 4kB so that we can quickly reach the point where jemalloc can
     * help us resize in-place, but after that point we grow by a factor
     * of 1.5x.
     *
     * FBVector doubles once it is bigger than 128kB, but I don't think we
     * actually want to because that's about when we want to stop growing.
     */
    size_t Buffer::next_alloc_size(size_t sz) {
        if (sz < malloc_utils::jemallocMinInPlaceExpandable) {
            return sz * 2;
        }
#if 0
        else if (sz > (128<<10)) {
            return sz * 2;
        }
#endif
        else {
            return (sz * 3 + 1) / 2;
        }
    }

    void Buffer::grow(size_t sz) {
        size_t new_capacity = _capacity;
        while (new_capacity < _end + sz) {
            new_capacity = next_alloc_size(new_capacity);
        }
        assert(new_capacity >= _capacity);  // overflow?
        if (new_capacity > _capacity) {
            // This section isn't exception-safe, but smartRealloc already
            // isn't.  The only thing we can throw in here is
            // std::bad_alloc, in which case we're kind of screwed anyway.
            new_capacity = malloc_utils::goodMallocSize(new_capacity);
            _buf.reset(malloc_utils::smartRealloc(_buf.release(), new_capacity, 0, 0, _capacity));
        }
    }

} // namespace ftcxx
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <stack>
#include <map>
#include <assert.h>
#include <fstream>

// From git file
#include "include/yaml.h"
#include "yaml-cpp/yaml.h"

// ---------------------------------------------------------------------------------
// ------------------------------- libyaml test code -------------------------------
// ---------------------------------------------------------------------------------

bool positionAnalysis(std::string& add_to_me, char reference_character, bool map_mode)
{
    if (reference_character == 'M')
    {
        if (map_mode)
        {
            add_to_me += "K: ";
        }
        else
        {
            add_to_me += "V: ";
        }
        return !map_mode;
    }
    else if (reference_character == 'S')
    {
        add_to_me += "L: ";
    }
    else
    {
        add_to_me += "U: ";
    }

    return map_mode;
}

void addToMap(std::map<std::string, std::string> & anchor_map,
    std::string& anchor, std::string& anchor_data)
{
    if (&anchor != nullptr)
    {
        if (anchor_map.count(anchor))
        {
            anchor_map[anchor] = anchor_data;
        }
        else
        {
            anchor_map.insert({anchor, anchor_data});
        }
    }
}

void addInfoToDataStack(std::stack<std::string>& anchor_data,
    std::string info)
{
    if (!anchor_data.empty())
    {
        std::string& temp = anchor_data.top();
        temp += info;
    }
    else
    {
        anchor_data.push(info);
    }
}

std::string parseLibyaml(std::string name_of_file)
{
    FILE *input;
    yaml_parser_t parser;
    yaml_event_t event;

    std::string libyaml_final_output = "";

    std::string relevant_saving_info = "";

    bool interest_in_saving = false;

    int subtract_count = 2;

    std::map<std::string, std::string> anchor_map;

    std::stack<std::string> anchor_save_stack;

    std::stack<std::string> anchor_data_save_stack;

    std::stack<char> mode_stack;

    mode_stack.push(' ');

    std::stack<bool> map_mode_stack;

    bool map_mode = true;

    input = fopen(name_of_file.c_str(), "rb");

    assert(input);

    if (!yaml_parser_initialize(&parser))
    {
        return "ERROR: Could not initialize the parser object\n";
    }
    yaml_parser_set_input_file(&parser, input);

    while (true)
    {
        std::string local_event_output = "";

        yaml_event_type_t type;

        if (!yaml_parser_parse(&parser, &event))
        {
            if ( parser.problem_mark.line || parser.problem_mark.column )
            {
                fprintf(stderr, "Parse error: %s\nLine: %lu Column: %lu\n",
                    parser.problem,
                    (unsigned long)parser.problem_mark.line + 1,
                    (unsigned long)parser.problem_mark.column + 1);
            }
            else {
                fprintf(stderr, "Parse error: %s\n", parser.problem);
            }
            return "ERROR: Bad parsing";
        }
        type = event.type;

        switch (type)
        {
            case YAML_STREAM_END_EVENT:
                if (!anchor_save_stack.empty() && interest_in_saving)
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                    interest_in_saving = false;
                    subtract_count = 2;
                }

                break;
            case YAML_DOCUMENT_END_EVENT:

                if (!anchor_save_stack.empty() && interest_in_saving)
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                    interest_in_saving = false;
                    subtract_count = 2;
                }

                break;
            case YAML_MAPPING_START_EVENT:
                if (!mode_stack.empty())
                {
                    positionAnalysis(local_event_output, mode_stack.top(), map_mode);
                }

                if (mode_stack.top()=='M')
                {
                    map_mode_stack.push(!map_mode);
                }

                mode_stack.push('M');

                map_mode = true;

                if (event.data.mapping_start.anchor)
                {
                    anchor_save_stack.push(((char*)event.data.mapping_start.anchor));
                    interest_in_saving = true;
                    subtract_count = 2;
                }
                else
                {
                    local_event_output += std::string((char*)event.data.scalar.value, event.data.scalar.length);
                }

                if (event.data.mapping_start.tag)
                {
                    std::string temp_translator = ((char*)event.data.mapping_start.tag);

                    local_event_output += temp_translator + " \n";
                }
                else
                {
                    local_event_output += "\n";
                }

                break;
            case YAML_MAPPING_END_EVENT:
                mode_stack.pop();

                if(mode_stack.top()=='M')
                {
                    map_mode = map_mode_stack.top();
                    map_mode_stack.pop();
                }

                if (!anchor_save_stack.empty() && interest_in_saving)
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                    interest_in_saving = false;
                    subtract_count = 2;
                }

                break;
            case YAML_SEQUENCE_START_EVENT:
                if (!mode_stack.empty())
                {
                    map_mode = positionAnalysis(local_event_output, mode_stack.top(), map_mode);
                }

                mode_stack.push('S');

                if (event.data.sequence_start.anchor)
                if (event.data.scalar.anchor)
                {
                    anchor_save_stack.push((char*)event.data.sequence_start.anchor);
                    interest_in_saving = true;
                    subtract_count = 2;
                }
                else
                {
                    local_event_output += std::string((char*)event.data.scalar.value, event.data.scalar.length);
                }

                if (event.data.sequence_start.tag)
                {
                    std::string temp_translator = ((char*)event.data.sequence_start.tag);

                    local_event_output += (temp_translator + " \n");
                }
                else
                {
                    local_event_output += "\n";
                }

                break;
            case YAML_SEQUENCE_END_EVENT:
                mode_stack.pop();

                if (!anchor_save_stack.empty() && interest_in_saving)
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                    interest_in_saving = false;
                    subtract_count = 2;
                }

                break;
            case YAML_SCALAR_EVENT:
                map_mode = positionAnalysis(local_event_output, mode_stack.top(), map_mode);

                if (event.data.scalar.tag)
                {
                    std::string temp_translator = ((char*)event.data.scalar.tag);

                    local_event_output += temp_translator + " - ";
                }
                else
                {
                    local_event_output += "- ";
                }

                if (event.data.scalar.anchor)
                {
                    anchor_save_stack.push((char*)event.data.scalar.anchor);
                    interest_in_saving = true;
                    subtract_count = 2;
                }
                else
                {
                    local_event_output += std::string((char*)event.data.scalar.value, event.data.scalar.length);

                    local_event_output += ("\n");
                }

                break;
            case YAML_ALIAS_EVENT:
            {
                std::string temp_translator = ((char*) event.data.alias.anchor);

                std::string& temp_holder = anchor_map[temp_translator];

                if (!temp_holder.empty())
                {
                    map_mode = positionAnalysis(local_event_output, mode_stack.top(), map_mode);
                    local_event_output += "\n" + temp_holder;
                }
                else
                {
                    yaml_event_delete(&event);

                    assert(!fclose(input));

                    yaml_parser_delete(&parser);
                    return "the referenced anchor is not defined";
                }
                break;
            }
            default:
                break;
        }

        yaml_event_delete(&event);

        if (type == YAML_STREAM_END_EVENT)
            break;

        if(subtract_count <= 1 && interest_in_saving)
        {
            addInfoToDataStack(anchor_data_save_stack, local_event_output);
        }

        if(interest_in_saving)
        {
            subtract_count--;
        }

        libyaml_final_output += local_event_output;

    }

    assert(!fclose(input));

    yaml_parser_delete(&parser);

    fflush(stdout);

    return libyaml_final_output;
}

// ---------------------------------------------------------------------------------
// ------------------------------ yaml-cpp test code -------------------------------
// ---------------------------------------------------------------------------------

std::string parseYamlCppNode(YAML::Node& head)
{
    std::stack <YAML::Node> iteration_list_stack;

    std::stack <std::string> additional_info_stack;

    iteration_list_stack.push(head);
    additional_info_stack.push("U");

    std::string yamlcpp_final_output = "";

    while (!iteration_list_stack.empty())
    {
        YAML::Node base_iterator = iteration_list_stack.top();
        iteration_list_stack.pop();

        yamlcpp_final_output += additional_info_stack.top() + ": ";
        additional_info_stack.pop();

        const std::string& tag_holder = base_iterator.Tag();

        if(tag_holder != "?" && tag_holder != "!")
        {
            yamlcpp_final_output += tag_holder + " ";
        }

        switch (base_iterator.Type())
        {
            case YAML::NodeType::Null:
            {
                 yamlcpp_final_output = "";
                break;
            }
            case YAML::NodeType::Scalar:
            {
                yamlcpp_final_output +=  "- " + base_iterator.as<std::string>() + "\n";
                break;
            }
            case YAML::NodeType::Sequence:
            {
                yamlcpp_final_output += "\n";
                for (int i = base_iterator.size() - 1; i >= 0; i--)
                {
                    iteration_list_stack.push(base_iterator[i]);
                    additional_info_stack.push("L");
                }

                break;
            }
            case YAML::NodeType::Map:
            {
                yamlcpp_final_output += "\n";
                std::stack <YAML::const_iterator> loca_iterators_temp_stack;

                for (YAML::const_iterator it = base_iterator.begin(); it != base_iterator.end(); ++it)
                {
                    loca_iterators_temp_stack.push(it);
                }

                while (!loca_iterators_temp_stack.empty())
                {
                    YAML::const_iterator it = loca_iterators_temp_stack.top();
                    loca_iterators_temp_stack.pop();

                    iteration_list_stack.push(it->second);
                    additional_info_stack.push("V");
                    iteration_list_stack.push(it->first);
                    additional_info_stack.push("K");
                }
                break;
            }
            case YAML::NodeType::Undefined:
            {
                yamlcpp_final_output += "- Undef \n";

                break;
            }
            default:
            {
                yamlcpp_final_output += "- ERROR: Unknown Input Type \n";
            }
        }
    }
    return yamlcpp_final_output;
}

// ---------------------------------------------------------------------------------
// ---------------------------------- testcode -------------------------------------
// ---------------------------------------------------------------------------------

bool compareStringsCustom(std::string compareMeOne, std::string compareMeTwo)
{
    std::string::iterator ptrOne = compareMeOne.begin();
    std::string::iterator ptrTwo = compareMeTwo.begin();

    while (*ptrOne == *ptrTwo && ((ptrOne != compareMeOne.end()) || (ptrTwo != compareMeTwo.end())))
    {
        if(*ptrOne == *ptrTwo)
        {
            std::cout << *ptrTwo;
        }
        ptrOne++;
        ptrTwo++;
    }

    if(!((ptrOne == compareMeOne.end())  && (ptrTwo == compareMeTwo.end())))
    {
        std::cout << "(X)";
        return false;
    }
    else
    {
        return true;
    }
}

// ---------------------------------------------------------------------------------
// -------------------------------------- main -------------------------------------
// ---------------------------------------------------------------------------------
int main(int argc, char* args[])
{
    std::cout << "----------- libyaml tests -----------" << std::endl;

    // parseLibyaml(args[1]);

    std::string libyaml_final_output = parseLibyaml(args[1]);
    std::cout << libyaml_final_output << "(END)" << std::endl;

    std::cout << "----------- yaml-cpp tests -----------" << std::endl;

    std::string yamlcpp_final_output;
    try
    {
        YAML::Node node = YAML::LoadFile(args[1]);
        // YAML::Node node = YAML::Load("[1, 2, 3]");
        std::cout << "Node type: " << node.Type() << std::endl;

        yamlcpp_final_output = parseYamlCppNode(node);
    }
    catch (const std::exception& err)
    {
        yamlcpp_final_output = err.what();
    }

    std::cout << "--------yaml-cpp Output:" << std::endl;
    std::cout << yamlcpp_final_output << "(END)" << std::endl;
    std::cout << "--------" << std::endl;
    std::cout << "- Conclusion: " << std::endl;

    if (compareStringsCustom(libyaml_final_output, yamlcpp_final_output))
    {
        std::cout << "(END)" << std::endl;
        std::cout << "Cases equal!" << std::endl;
    }
    else
    {
        std::cout << "(END)" << std::endl;
        std::cout << "Cases different!" << std::endl;
    }

    return 0;
}

// \0 in the middle<commit_msg>Small libyaml refactoring on adding to maps<commit_after>#include <iostream>
#include <string>
#include <stack>
#include <map>
#include <assert.h>
#include <fstream>

// From git file
#include "include/yaml.h"
#include "yaml-cpp/yaml.h"

// ---------------------------------------------------------------------------------
// ------------------------------- libyaml test code -------------------------------
// ---------------------------------------------------------------------------------

bool positionAnalysis(std::string& add_to_me, char reference_character, bool map_mode)
{
    if (reference_character == 'M')
    {
        if (map_mode)
        {
            add_to_me += "K: ";
        }
        else
        {
            add_to_me += "V: ";
        }
        return !map_mode;
    }
    else if (reference_character == 'S')
    {
        add_to_me += "L: ";
    }
    else
    {
        add_to_me += "U: ";
    }

    return map_mode;
}

void addToMap(std::map<std::string, std::string>& anchor_map,
    std::string& anchor, std::string& anchor_data)
{
    if (&anchor != nullptr)
    {
        if (anchor_map.count(anchor))
        {
            anchor_map[anchor] = anchor_data;
        }
        else
        {
            anchor_map.insert({anchor, anchor_data});
        }
    }
}

bool addToMapDirective(std::map<std::string, std::string>& anchor_map,
    std::stack<std::string>& anchor_save_stack, std::stack<std::string>& anchor_data_save_stack,
    int& subtract_count, bool interest_in_saving)
{
    if (!anchor_save_stack.empty() && interest_in_saving)
    {
        addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
        anchor_save_stack.pop();
        anchor_data_save_stack.pop();
        subtract_count = 2;
        return false;
    }
    return interest_in_saving;
}

void addInfoToDataStack(std::stack<std::string>& anchor_data,
    std::string info)
{
    if (!anchor_data.empty())
    {
        std::string& temp = anchor_data.top();
        temp += info;
    }
    else
    {
        anchor_data.push(info);
    }
}

std::string parseLibyaml(std::string name_of_file)
{
    FILE *input;
    yaml_parser_t parser;
    yaml_event_t event;

    std::string libyaml_final_output = "";

    std::string relevant_saving_info = "";

    bool interest_in_saving = false;

    int subtract_count = 2;

    std::map<std::string, std::string> anchor_map;

    std::stack<std::string> anchor_save_stack;

    std::stack<std::string> anchor_data_save_stack;

    std::stack<char> mode_stack;

    mode_stack.push(' ');

    std::stack<bool> map_mode_stack;

    bool map_mode = true;

    input = fopen(name_of_file.c_str(), "rb");

    assert(input);

    if (!yaml_parser_initialize(&parser))
    {
        return "ERROR: Could not initialize the parser object\n";
    }
    yaml_parser_set_input_file(&parser, input);

    while (true)
    {
        std::string local_event_output = "";

        yaml_event_type_t type;

        if (!yaml_parser_parse(&parser, &event))
        {
            if ( parser.problem_mark.line || parser.problem_mark.column )
            {
                fprintf(stderr, "Parse error: %s\nLine: %lu Column: %lu\n",
                    parser.problem,
                    (unsigned long)parser.problem_mark.line + 1,
                    (unsigned long)parser.problem_mark.column + 1);
            }
            else {
                fprintf(stderr, "Parse error: %s\n", parser.problem);
            }
            return "ERROR: Bad parsing";
        }
        type = event.type;

        switch (type)
        {
            case YAML_STREAM_END_EVENT:

            interest_in_saving = addToMapDirective(anchor_map, anchor_save_stack,
                anchor_data_save_stack, subtract_count, interest_in_saving);

                break;
            case YAML_DOCUMENT_END_EVENT:

                interest_in_saving = addToMapDirective(anchor_map, anchor_save_stack,
                    anchor_data_save_stack, subtract_count, interest_in_saving);

                break;
            case YAML_MAPPING_START_EVENT:
                if (!mode_stack.empty())
                {
                    positionAnalysis(local_event_output, mode_stack.top(), map_mode);
                }

                if (mode_stack.top()=='M')
                {
                    map_mode_stack.push(!map_mode);
                }

                mode_stack.push('M');

                map_mode = true;

                if (event.data.mapping_start.anchor)
                {
                    anchor_save_stack.push(((char*)event.data.mapping_start.anchor));
                    interest_in_saving = true;
                    subtract_count = 2;
                }
                else
                {
                    local_event_output +=
                        std::string((char*)event.data.scalar.value, event.data.scalar.length);
                }

                if (event.data.mapping_start.tag)
                {
                    std::string temp_translator = ((char*)event.data.mapping_start.tag);

                    local_event_output += temp_translator + " \n";
                }
                else
                {
                    local_event_output += "\n";
                }

                break;
            case YAML_MAPPING_END_EVENT:
                mode_stack.pop();

                if(mode_stack.top()=='M')
                {
                    map_mode = map_mode_stack.top();
                    map_mode_stack.pop();
                }

            interest_in_saving = addToMapDirective(anchor_map, anchor_save_stack,
                anchor_data_save_stack, subtract_count, interest_in_saving);

                break;
            case YAML_SEQUENCE_START_EVENT:
                if (!mode_stack.empty())
                {
                    map_mode = positionAnalysis(local_event_output, mode_stack.top(), map_mode);
                }

                mode_stack.push('S');

                if (event.data.sequence_start.anchor)
                if (event.data.scalar.anchor)
                {
                    anchor_save_stack.push((char*)event.data.sequence_start.anchor);
                    interest_in_saving = true;
                    subtract_count = 2;
                }
                else
                {
                    local_event_output += std::string((char*)event.data.scalar.value, event.data.scalar.length);
                }

                if (event.data.sequence_start.tag)
                {
                    std::string temp_translator = ((char*)event.data.sequence_start.tag);

                    local_event_output += (temp_translator + " \n");
                }
                else
                {
                    local_event_output += "\n";
                }

                break;
            case YAML_SEQUENCE_END_EVENT:
                mode_stack.pop();

                interest_in_saving = addToMapDirective(anchor_map, anchor_save_stack,
                    anchor_data_save_stack, subtract_count, interest_in_saving);

                break;
            case YAML_SCALAR_EVENT:
                map_mode = positionAnalysis(local_event_output, mode_stack.top(), map_mode);

                if (event.data.scalar.tag)
                {
                    std::string temp_translator = ((char*)event.data.scalar.tag);

                    local_event_output += temp_translator + " - ";
                }
                else
                {
                    local_event_output += "- ";
                }

                if (event.data.scalar.anchor)
                {
                    anchor_save_stack.push((char*)event.data.scalar.anchor);
                    interest_in_saving = true;
                    subtract_count = 2;
                }
                else
                {
                    local_event_output += std::string((char*)event.data.scalar.value, event.data.scalar.length);

                    local_event_output += ("\n");
                }

                break;
            case YAML_ALIAS_EVENT:
            {
                std::string temp_translator = ((char*) event.data.alias.anchor);

                std::string& temp_holder = anchor_map[temp_translator];

                if (!temp_holder.empty())
                {
                    map_mode = positionAnalysis(local_event_output, mode_stack.top(), map_mode);
                    local_event_output += "\n" + temp_holder;
                }
                else
                {
                    yaml_event_delete(&event);

                    assert(!fclose(input));

                    yaml_parser_delete(&parser);
                    return "the referenced anchor is not defined";
                }
                break;
            }
            default:
                break;
        }

        yaml_event_delete(&event);

        if (type == YAML_STREAM_END_EVENT)
            break;

        if(subtract_count <= 1 && interest_in_saving)
        {
            addInfoToDataStack(anchor_data_save_stack, local_event_output);
        }

        if(interest_in_saving)
        {
            subtract_count--;
        }

        libyaml_final_output += local_event_output;

    }

    assert(!fclose(input));

    yaml_parser_delete(&parser);

    fflush(stdout);

    return libyaml_final_output;
}

// ---------------------------------------------------------------------------------
// ------------------------------ yaml-cpp test code -------------------------------
// ---------------------------------------------------------------------------------

std::string parseYamlCppNode(YAML::Node& head)
{
    std::stack <YAML::Node> iteration_list_stack;

    std::stack <std::string> additional_info_stack;

    iteration_list_stack.push(head);
    additional_info_stack.push("U");

    std::string yamlcpp_final_output = "";

    while (!iteration_list_stack.empty())
    {
        YAML::Node base_iterator = iteration_list_stack.top();
        iteration_list_stack.pop();

        yamlcpp_final_output += additional_info_stack.top() + ": ";
        additional_info_stack.pop();

        const std::string& tag_holder = base_iterator.Tag();

        if(tag_holder != "?" && tag_holder != "!")
        {
            yamlcpp_final_output += tag_holder + " ";
        }

        switch (base_iterator.Type())
        {
            case YAML::NodeType::Null:
            {
                 yamlcpp_final_output = "";
                break;
            }
            case YAML::NodeType::Scalar:
            {
                yamlcpp_final_output +=  "- " + base_iterator.as<std::string>() + "\n";
                break;
            }
            case YAML::NodeType::Sequence:
            {
                yamlcpp_final_output += "\n";
                for (int i = base_iterator.size() - 1; i >= 0; i--)
                {
                    iteration_list_stack.push(base_iterator[i]);
                    additional_info_stack.push("L");
                }

                break;
            }
            case YAML::NodeType::Map:
            {
                yamlcpp_final_output += "\n";
                std::stack <YAML::const_iterator> loca_iterators_temp_stack;

                for (YAML::const_iterator it = base_iterator.begin(); it != base_iterator.end(); ++it)
                {
                    loca_iterators_temp_stack.push(it);
                }

                while (!loca_iterators_temp_stack.empty())
                {
                    YAML::const_iterator it = loca_iterators_temp_stack.top();
                    loca_iterators_temp_stack.pop();

                    iteration_list_stack.push(it->second);
                    additional_info_stack.push("V");
                    iteration_list_stack.push(it->first);
                    additional_info_stack.push("K");
                }
                break;
            }
            case YAML::NodeType::Undefined:
            {
                yamlcpp_final_output += "- Undef \n";

                break;
            }
            default:
            {
                yamlcpp_final_output += "- ERROR: Unknown Input Type \n";
            }
        }
    }
    return yamlcpp_final_output;
}

// ---------------------------------------------------------------------------------
// ---------------------------------- testcode -------------------------------------
// ---------------------------------------------------------------------------------

bool compareStringsCustom(std::string compareMeOne, std::string compareMeTwo)
{
    std::string::iterator ptrOne = compareMeOne.begin();
    std::string::iterator ptrTwo = compareMeTwo.begin();

    while (*ptrOne == *ptrTwo && ((ptrOne != compareMeOne.end()) || (ptrTwo != compareMeTwo.end())))
    {
        if(*ptrOne == *ptrTwo)
        {
            std::cout << *ptrTwo;
        }
        ptrOne++;
        ptrTwo++;
    }

    if(!((ptrOne == compareMeOne.end())  && (ptrTwo == compareMeTwo.end())))
    {
        std::cout << "(X)";
        return false;
    }
    else
    {
        return true;
    }
}

// ---------------------------------------------------------------------------------
// -------------------------------------- main -------------------------------------
// ---------------------------------------------------------------------------------
int main(int argc, char* args[])
{
    std::cout << "----------- libyaml tests -----------" << std::endl;

    // parseLibyaml(args[1]);

    std::string libyaml_final_output = parseLibyaml(args[1]);
    std::cout << libyaml_final_output << "(END)" << std::endl;

    std::cout << "----------- yaml-cpp tests -----------" << std::endl;

    std::string yamlcpp_final_output;
    try
    {
        YAML::Node node = YAML::LoadFile(args[1]);

        // YAML::Node node = YAML::Load("[1, 2, 3]");
        std::cout << "Node type: " << node.Type() << std::endl;

        yamlcpp_final_output = parseYamlCppNode(node);
    }
    catch (const std::exception& err)
    {
        yamlcpp_final_output = err.what();
    }
    std::cout << "Four" << std::endl;

    std::cout << "--------yaml-cpp Output:" << std::endl;
    std::cout << yamlcpp_final_output << "(END)" << std::endl;
    std::cout << "--------" << std::endl;
    std::cout << "- Conclusion: " << std::endl;

    if (compareStringsCustom(libyaml_final_output, yamlcpp_final_output))
    {
        std::cout << "(END)" << std::endl;
        std::cout << "Cases equal!" << std::endl;
    }
    else
    {
        std::cout << "(END)" << std::endl;
        std::cout << "Cases different!" << std::endl;
    }

    return 0;
}

// \0 in the middle<|endoftext|>