blob: f50d80ee7688d77fba9916898f529ef5afb51d38 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 "AttributeListImpl.hpp"
#include <algorithm>
#include <cassert>
#include <xalanc/Include/XalanMemMgrAutoPtr.hpp>
#include <xalanc/Include/STLHelper.hpp>
#include "AttributeVectorEntry.hpp"
namespace XALAN_CPP_NAMESPACE {
AttributeListImpl::AttributeListImpl(MemoryManager& theManager) :
AttributeListType(),
m_AttributeVector(theManager),
m_cacheVector(theManager)
{
}
AttributeListImpl::~AttributeListImpl()
{
// Clean up everything...
clear();
assert(m_AttributeVector.empty() == true);
deleteEntries(m_cacheVector);
}
AttributeListImpl::AttributeListImpl(const AttributeListImpl& theSource,
MemoryManager& theManager) :
AttributeListType(),
m_AttributeVector(theManager),
m_cacheVector(theManager)
{
// Use the assignment operator to do the dirty work...
*this = theSource;
assert(getLength() == theSource.getLength());
}
AttributeListImpl::AttributeListImpl(const AttributeListType& theSource,
MemoryManager& theManager) :
AttributeListType(),
m_AttributeVector(theManager),
m_cacheVector(theManager)
{
// Use the assignment operator to do the dirty work...
*this = theSource;
assert(getLength() == theSource.getLength());
}
void
AttributeListImpl::deleteEntries(AttributeVectorType& theVector)
{
// Delete all of the objects in the vector.
std::for_each(
theVector.begin(),
theVector.end(),
DeleteFunctor<AttributeVectorEntry>(theVector.getMemoryManager()));
}
AttributeListImpl&
AttributeListImpl::operator=(const AttributeListImpl& 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.
AttributeVectorType tempVector(getMemoryManager());
const XalanSize_t 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<AttributeVectorType,
DeleteFunctor<AttributeVectorEntry> > theGuard(tempVector);
typedef AttributeVectorType::const_iterator const_iterator;
const const_iterator theEnd = theRHS.m_AttributeVector.end();
// Copy the vector entries, and build the index map...
for(const_iterator i = theRHS.m_AttributeVector.begin(); i != theEnd; ++i)
{
AttributeVectorEntry* 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()));
}
// OK, we're safe, so swap the contents of the
// containers. This is guaranteed not to throw.
m_AttributeVector.swap(tempVector);
}
assert(getLength() == theLength);
}
return *this;
}
AttributeListImpl&
AttributeListImpl::operator=(const AttributeListType& 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.
AttributeListImpl theTempList(getMemoryManager());
const XalanSize_t theLength = theRHS.getLength();
theTempList.reserve(theLength);
// Add each attribute.
for(XalanSize_t i = 0; i < theLength; i++)
{
theTempList.addAttribute(
theRHS.getName(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;
}
XalanSize_t
AttributeListImpl::getLength() const
{
// Make sure the mismatch between Xerces and vector<> doesn't cause a problem...
assert(m_AttributeVector.size() == unsigned(m_AttributeVector.size()));
return unsigned(m_AttributeVector.size());
}
const XMLCh*
AttributeListImpl::getName(const XalanSize_t index) const
{
assert(index < getLength());
return &*m_AttributeVector[index]->m_Name.begin();
}
const XMLCh*
AttributeListImpl::getType(const XalanSize_t index) const
{
assert(index < getLength());
return &*m_AttributeVector[index]->m_Type.begin();
}
const XMLCh*
AttributeListImpl::getValue(const XalanSize_t index) const
{
assert(index < getLength());
return &*m_AttributeVector[index]->m_Value.begin();
}
const XMLCh*
AttributeListImpl:: getValue(const char* const /*name*/) const
{
assert(0);
return 0;
}
struct NameCompareFunctor
{
NameCompareFunctor(const XMLCh* theName) :
m_name(theName)
{
}
bool
operator()(const AttributeVectorEntry* theEntry) const
{
return equals(&*theEntry->m_Name.begin(), m_name);
}
private:
const XMLCh* const m_name;
};
const XMLCh*
AttributeListImpl::getType(const XMLCh* const name) const
{
assert(name != 0);
const AttributeVectorType::const_iterator i =
std::find_if(
m_AttributeVector.begin(),
m_AttributeVector.end(),
NameCompareFunctor(name));
if (i != m_AttributeVector.end())
{
// Found it, so return a pointer to the type.
return &*(*i)->m_Type.begin();
}
else
{
return 0;
}
}
const XMLCh*
AttributeListImpl::getValue(const XMLCh* const name) const
{
assert(name != 0);
const AttributeVectorType::const_iterator i =
std::find_if(
m_AttributeVector.begin(),
m_AttributeVector.end(),
NameCompareFunctor(name));
if (i != m_AttributeVector.end())
{
// Found it, so return a pointer to the value.
return &*(*i)->m_Value.begin();
}
else
{
return 0;
}
}
void
AttributeListImpl::clear()
{
m_cacheVector.insert(m_cacheVector.end(), m_AttributeVector.begin(), m_AttributeVector.end());
// Clear everything out.
m_AttributeVector.clear();
}
bool
AttributeListImpl::addAttribute(
const XMLCh* name,
const XMLCh* type,
const XMLCh* value)
{
assert(name != 0);
assert(type != 0);
assert(value != 0);
bool fResult = false;
using std::find_if;
using std::copy;
typedef AttributeVectorEntry::XMLChVectorType XMLChVectorType;
// Update the attribute, if it's already there...
const AttributeVectorType::const_iterator i =
find_if(
m_AttributeVector.begin(),
m_AttributeVector.end(),
NameCompareFunctor(name));
if (i != m_AttributeVector.end())
{
// This is a special optimization for type, since it's (almost) always "CDATA".
if (equals(type, &*(*i)->m_Type.begin()) == false)
{
// If necessary, create the a new vector and swap them. Otherwise,
// just copy the new data in.
const XMLCh* const theNewTypeEnd = AttributeVectorEntry::endArray(type) + 1;
if ((*i)->m_Type.capacity() < XMLChVectorType::size_type(theNewTypeEnd - type))
{
XMLChVectorType theNewType(type, theNewTypeEnd, getMemoryManager());
theNewType.swap((*i)->m_Type);
}
else
{
copy(type, theNewTypeEnd, (*i)->m_Type.begin());
}
}
const XMLCh* const theNewValueEnd = AttributeVectorEntry::endArray(value) + 1;
const XMLChVectorType::size_type theNewSize =
XMLChVectorType::size_type(theNewValueEnd - value);
// If necessary, create the a new vector and swap them. Otherwise,
// just copy the new data in.
if ((*i)->m_Value.capacity() < theNewSize)
{
XMLChVectorType theNewValue(value, theNewValueEnd, getMemoryManager());
theNewValue.swap((*i)->m_Value);
}
else
{
(*i)->m_Value.resize(theNewSize);
copy(value, theNewValueEnd, (*i)->m_Value.begin());
}
}
else
{
if (m_AttributeVector.capacity() == 0)
{
m_AttributeVector.reserve(eDefaultVectorSize);
}
typedef XalanMemMgrAutoPtr<AttributeVectorEntry> AutoPtr;
AutoPtr theEntry(getMemoryManager(), getNewEntry(name, type, value));
// Add the new one.
m_AttributeVector.push_back(theEntry.get());
theEntry.release();
fResult = true;
}
return fResult;
}
AttributeVectorEntry*
AttributeListImpl::getNewEntry(
const XMLCh* name,
const XMLCh* type,
const XMLCh* value)
{
if (m_cacheVector.empty() == true)
{
return AttributeVectorEntry::create(name, value, type,getMemoryManager());
}
else
{
AttributeVectorEntry* 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_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);
m_cacheVector.pop_back();
return theEntry;
}
}
bool
AttributeListImpl::removeAttribute(const XMLCh* name)
{
assert(name != 0);
bool fResult = false;
// Update the attribute, if it's already there...
const AttributeVectorType::iterator i =
std::find_if(
m_AttributeVector.begin(),
m_AttributeVector.end(),
NameCompareFunctor(name));
if (i != m_AttributeVector.end())
{
m_cacheVector.push_back(*i);
m_AttributeVector.erase(i);
fResult = true;
}
return fResult;
}
}