blob: c09243237d7aaea785654249427de860774e9ace [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Class header file.
#include "AttributesImpl.hpp"
#include <algorithm>
#include <cassert>
#include <xalanc/Include/XalanAutoPtr.hpp>
#include <xalanc/Include/STLHelper.hpp>
#include "AttributeVectorEntryExtended.hpp"
XALAN_CPP_NAMESPACE_BEGIN
AttributesImpl::AttributesImpl() :
AttributesType(),
m_attributesVector(),
m_cacheVector()
{
}
AttributesImpl::~AttributesImpl()
{
// Clean up everything...
clear();
assert(m_attributesVector.empty() == true);
deleteEntries(m_cacheVector);
}
AttributesImpl::AttributesImpl(const AttributesImpl& theSource) :
AttributesType(),
m_attributesVector()
{
// Use the assignment operator to do the dirty work...
*this = theSource;
assert(getLength() == theSource.getLength());
}
AttributesImpl::AttributesImpl(const AttributesType& theSource) :
AttributesType(),
m_attributesVector()
{
// Use the assignment operator to do the dirty work...
*this = theSource;
assert(getLength() == theSource.getLength());
}
void
AttributesImpl::deleteEntries(AttributesVectorType& theVector)
{
// Delete all of the objects in the vector.
XALAN_STD_QUALIFIER for_each(
theVector.begin(),
theVector.end(),
DeleteFunctor<AttributeVectorEntryExtended>());
}
AttributesImpl&
AttributesImpl::operator=(const AttributesImpl& theRHS)
{
if (this != &theRHS)
{
// Note that we can't chain up to our base class operator=()
// because it's private.
// Some temporary structures to hold everything
// until we're done.
AttributesVectorType tempVector;
const unsigned int theLength = theRHS.getLength();
if (theLength > 0)
{
// Reserve the appropriate capacity right now...
tempVector.reserve(theLength);
// This will delete everything in tempVector when we're done...
CollectionDeleteGuard<AttributesVectorType,
DeleteFunctor<AttributeVectorEntryExtended> > theGuard(tempVector);
typedef AttributesVectorType::const_iterator const_iterator;
const const_iterator theEnd = theRHS.m_attributesVector.end();
// Copy the vector entries, and build the index map...
for(const_iterator i = theRHS.m_attributesVector.begin(); i != theEnd; ++i)
{
AttributeVectorEntryExtended* const theEntry = *i;
assert(theEntry != 0);
// Add the item...
tempVector.push_back(
getNewEntry(
&*theEntry->m_Name.begin(),
&*theEntry->m_Type.begin(),
&*theEntry->m_Value.begin(),
&*theEntry->m_uri.begin(),
&*theEntry->m_localName.begin()));
}
// OK, we're safe, so swap the contents of the
// containers. This is guaranteed not to throw.
m_attributesVector.swap(tempVector);
}
assert(getLength() == theLength);
}
return *this;
}
AttributesImpl&
AttributesImpl::operator=(const AttributesType& theRHS)
{
if (this != &theRHS)
{
// Note that we can't chain up to our base class operator=()
// because it's private.
// Add all of the attributes to this temp list,
// then swap at the end. This means we're exception
// safe and don't need any try blocks.
AttributesImpl theTempList;
const unsigned int theLength = theRHS.getLength();
theTempList.reserve(theLength);
// Add each attribute.
for(unsigned int i = 0; i < theLength; i++)
{
theTempList.addAttribute(
theRHS.getURI(i),
theRHS.getLocalName(i),
theRHS.getQName(i),
theRHS.getType(i),
theRHS.getValue(i));
}
// Now that the temp list is built, swap everything. This is
// guaranteed not to throw.
swap(theTempList);
}
return *this;
}
unsigned int
AttributesImpl::getLength() const
{
return unsigned(m_attributesVector.size());
}
const XMLCh*
AttributesImpl::getURI(const unsigned int index) const
{
assert(index < getLength());
return &*m_attributesVector[index]->m_uri.begin();
}
const XMLCh*
AttributesImpl::getLocalName(const unsigned int index) const
{
assert(index < getLength());
return &*m_attributesVector[index]->m_localName.begin();
}
const XMLCh*
AttributesImpl::getQName(const unsigned int index) const
{
assert(index < getLength());
return &*m_attributesVector[index]->m_Name.begin();
}
const XMLCh*
AttributesImpl::getType(const unsigned int index) const
{
assert(index < getLength());
return &*m_attributesVector[index]->m_Type.begin();
}
const XMLCh*
AttributesImpl::getValue(const unsigned int index) const
{
assert(index < getLength());
return &*m_attributesVector[index]->m_Value.begin();
}
#if defined(XALAN_NEEDS_EXPLICIT_TEMPLATE_INSTANTIATION)
bool
AttributesImpl::NameCompareFunctor::operator()(const AttributeVectorEntryExtended* theEntry) const
{
return equals(&*theEntry->m_Name.begin(), m_qname);
}
bool
AttributesImpl::URIAndLocalNameCompareFunctor::operator()(const AttributeVectorEntryExtended* theEntry) const
{
return equals(&*theEntry->m_uri.begin(), m_uri) && equals(&*theEntry->m_localName.begin(), m_localName) ;
}
#else
struct NameCompareFunctor
{
NameCompareFunctor(const XMLCh* theQName) :
m_qname(theQName)
{
}
bool
operator()(const AttributeVectorEntryExtended* theEntry) const
{
return equals(&*theEntry->m_Name.begin(), m_qname);
}
private:
const XMLCh* const m_qname;
};
struct URIAndLocalNameCompareFunctor
{
URIAndLocalNameCompareFunctor(
const XMLCh* theURI,
const XMLCh* theLocalName) :
m_uri(theURI),
m_localName(theLocalName)
{
}
bool
operator()(const AttributeVectorEntryExtended* theEntry) const
{
return equals(&*theEntry->m_uri.begin(), m_uri) && equals(&*theEntry->m_localName.begin(), m_localName) ;
}
private:
const XMLCh* const m_uri;
const XMLCh* const m_localName;
};
#endif
const XMLCh*
AttributesImpl::getType(const XMLCh* const qname) const
{
const int theIndex = getIndex(qname);
if (theIndex == -1)
{
return 0;
}
else
{
return getType(theIndex);
}
}
const XMLCh*
AttributesImpl::getValue(const XMLCh* const qname) const
{
const int theIndex = getIndex(qname);
if (theIndex == -1)
{
return 0;
}
else
{
return getValue(theIndex);
}
}
const XMLCh*
AttributesImpl::getType(
const XMLCh* const uri,
const XMLCh* const localName) const
{
const int theIndex = getIndex(uri, localName);
if (theIndex == -1)
{
return 0;
}
else
{
return getType(theIndex);
}
}
const XMLCh*
AttributesImpl::getValue(
const XMLCh* const uri,
const XMLCh* const localName) const
{
const int theIndex = getIndex(uri, localName);
if (theIndex == -1)
{
return 0;
}
else
{
return getValue(theIndex);
}
}
int
AttributesImpl::getIndex(
const XMLCh* const uri,
const XMLCh* const localName) const
{
assert(uri != 0 && localName != 0);
const AttributesVectorType::const_iterator i =
XALAN_STD_QUALIFIER find_if(
m_attributesVector.begin(),
m_attributesVector.end(),
URIAndLocalNameCompareFunctor(uri, localName));
if (i != m_attributesVector.end())
{
// Found it, so return the index, which is the difference between
// begin() and i.
return int(i - m_attributesVector.begin());
}
else
{
return -1;
}
}
int
AttributesImpl::getIndex(const XMLCh* const qname) const
{
assert(qname != 0);
const AttributesVectorType::const_iterator i =
XALAN_STD_QUALIFIER find_if(
m_attributesVector.begin(),
m_attributesVector.end(),
NameCompareFunctor(qname));
if (i != m_attributesVector.end())
{
// Found it, so return the index, which is the difference between
// begin() and i.
return int(i - m_attributesVector.begin());
}
else
{
return -1;
}
}
void
AttributesImpl::clear()
{
m_cacheVector.insert(m_cacheVector.end(), m_attributesVector.begin(), m_attributesVector.end());
// Clear everything out.
m_attributesVector.clear();
}
void
AttributesImpl::addAttribute(
const XMLCh* uri,
const XMLCh* localName,
const XMLCh* name,
const XMLCh* type,
const XMLCh* value)
{
assert(name != 0);
assert(type != 0);
assert(value != 0);
typedef AttributeVectorEntry::XMLChVectorType XMLChVectorType;
if (m_attributesVector.capacity() == 0)
{
m_attributesVector.reserve(eDefaultVectorSize);
}
XalanAutoPtr<AttributeVectorEntryExtended> theEntry(getNewEntry(name, type, value, uri, localName));
// Add the new one.
m_attributesVector.push_back(theEntry.get());
// The entry is now safely in the vector, so release the
// XalanAutoPtr...
theEntry.release();
}
AttributeVectorEntryExtended*
AttributesImpl::getNewEntry(
const XMLCh* name,
const XMLCh* type,
const XMLCh* value,
const XMLCh* uri,
const XMLCh* localName)
{
assert(name != 0);
assert(type != 0);
assert(value != 0);
assert(uri != 0);
assert(localName != 0);
if (m_cacheVector.empty() == true)
{
return new AttributeVectorEntryExtended(name, value, type, uri, localName);
}
else
{
AttributeVectorEntryExtended* const theEntry =
m_cacheVector.back();
theEntry->clear();
assert(theEntry->m_Name.empty() == true && theEntry->m_Value.empty() == true &&
theEntry->m_Type.empty() == true && theEntry->m_uri.empty() == true &&
theEntry->m_localName.empty() == true);
theEntry->m_Name.insert(theEntry->m_Name.begin(), name, AttributeVectorEntry::endArray(name) + 1);
theEntry->m_Value.insert(theEntry->m_Value.begin(), value, AttributeVectorEntry::endArray(value) + 1);
theEntry->m_Type.insert(theEntry->m_Type.begin(), type, AttributeVectorEntry::endArray(type) + 1);
theEntry->m_uri.insert(theEntry->m_uri.begin(), uri, AttributeVectorEntry::endArray(uri) + 1);
theEntry->m_localName.insert(theEntry->m_localName.begin(), localName, AttributeVectorEntry::endArray(localName) + 1);
m_cacheVector.pop_back();
return theEntry;
}
}
bool
AttributesImpl::removeAttribute(const XMLCh* name)
{
assert(name != 0);
bool fResult = false;
// Update the attribute, if it's already there...
const AttributesVectorType::iterator i =
XALAN_STD_QUALIFIER find_if(
m_attributesVector.begin(),
m_attributesVector.end(),
NameCompareFunctor(name));
if (i != m_attributesVector.end())
{
m_cacheVector.push_back(*i);
m_attributesVector.erase(i);
fResult = true;
}
return fResult;
}
XALAN_CPP_NAMESPACE_END