diff options
86 files changed, 1537 insertions, 1363 deletions
diff --git a/document/src/tests/documenttestcase.cpp b/document/src/tests/documenttestcase.cpp index 3bbd5178055..a9e7b1897b2 100644 --- a/document/src/tests/documenttestcase.cpp +++ b/document/src/tests/documenttestcase.cpp @@ -5,6 +5,7 @@ #include <vespa/vdstestlib/cppunit/macros.h> #include <vespa/document/datatype/annotationreferencedatatype.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> #include <vespa/document/repo/configbuilder.h> #include <vespa/document/serialization/vespadocumentdeserializer.h> #include <vespa/document/serialization/vespadocumentserializer.h> @@ -19,6 +20,8 @@ using namespace document::config_builder; namespace document { +using namespace fieldvalue; + struct DocumentTest : public CppUnit::TestFixture { void testTraversing(); void testFieldPath(); @@ -105,7 +108,7 @@ void DocumentTest::testFieldPath() } } -class Handler : public FieldValue::IteratorHandler { +class Handler : public fieldvalue::IteratorHandler { public: Handler(); ~Handler(); @@ -185,7 +188,7 @@ void DocumentTest::testTraversing() std::string("<P<P<PP[PPP][<PP><PP>]>>>")); } -class VariableIteratorHandler : public FieldValue::IteratorHandler { +class VariableIteratorHandler : public IteratorHandler { public: VariableIteratorHandler(); ~VariableIteratorHandler(); @@ -268,7 +271,7 @@ DocumentTest::testVariables() } -class ModifyIteratorHandler : public FieldValue::IteratorHandler { +class ModifyIteratorHandler : public IteratorHandler { public: ModificationStatus doModify(FieldValue& fv) override { StringFieldValue* sfv = dynamic_cast<StringFieldValue*>(&fv); diff --git a/document/src/tests/fieldpathupdatetestcase.cpp b/document/src/tests/fieldpathupdatetestcase.cpp index 4a23f828921..4311e1059c2 100644 --- a/document/src/tests/fieldpathupdatetestcase.cpp +++ b/document/src/tests/fieldpathupdatetestcase.cpp @@ -1,6 +1,7 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/document/base/testdocman.h> #include <vespa/document/fieldvalue/fieldvalues.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> #include <vespa/document/select/node.h> #include <vespa/vespalib/io/fileutil.h> #include <vespa/vdstestlib/cppunit/macros.h> @@ -21,6 +22,8 @@ using namespace document::config_builder; namespace document { +using namespace fieldvalue; + struct FieldPathUpdateTestCase : public CppUnit::TestFixture { DocumentTypeRepo::SP _repo; DocumentType _foobar_type; @@ -259,7 +262,7 @@ void testSerialize(const DocumentTypeRepo& repo, const DocumentUpdate& a) { struct TestFieldPathUpdate : FieldPathUpdate { - struct TestIteratorHandler : FieldValue::IteratorHandler + struct TestIteratorHandler : fieldvalue::IteratorHandler { TestIteratorHandler(std::string& str) : _str(str) {} @@ -288,9 +291,9 @@ struct TestFieldPathUpdate : FieldPathUpdate TestFieldPathUpdate(const TestFieldPathUpdate& other); - std::unique_ptr<FieldValue::IteratorHandler> getIteratorHandler(Document&) const override + std::unique_ptr<IteratorHandler> getIteratorHandler(Document&) const override { - return std::unique_ptr<FieldValue::IteratorHandler>( + return std::unique_ptr<IteratorHandler>( new TestIteratorHandler(_str)); } diff --git a/document/src/vespa/document/fieldvalue/CMakeLists.txt b/document/src/vespa/document/fieldvalue/CMakeLists.txt index 8c76db54d5f..18ea4fc9368 100644 --- a/document/src/vespa/document/fieldvalue/CMakeLists.txt +++ b/document/src/vespa/document/fieldvalue/CMakeLists.txt @@ -10,6 +10,7 @@ vespa_add_library(document_fieldvalues OBJECT fieldvalue.cpp floatfieldvalue.cpp intfieldvalue.cpp + iteratorhandler.cpp literalfieldvalue.cpp longfieldvalue.cpp mapfieldvalue.cpp @@ -22,6 +23,7 @@ vespa_add_library(document_fieldvalues OBJECT structfieldvalue.cpp structuredfieldvalue.cpp tensorfieldvalue.cpp + variablemap.cpp weightedsetfieldvalue.cpp referencefieldvalue.cpp DEPENDS diff --git a/document/src/vespa/document/fieldvalue/annotationreferencefieldvalue.cpp b/document/src/vespa/document/fieldvalue/annotationreferencefieldvalue.cpp index 9863ee1c18a..cd6d43d2f4d 100644 --- a/document/src/vespa/document/fieldvalue/annotationreferencefieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/annotationreferencefieldvalue.cpp @@ -1,6 +1,7 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "annotationreferencefieldvalue.h" +#include <vespa/vespalib/util/xmlstream.h> #include <ostream> using std::ostream; @@ -23,8 +24,7 @@ int AnnotationReferenceFieldValue::compare(const FieldValue &other) const { return (getDataType()->getId() - other.getDataType()->getId()); } -void AnnotationReferenceFieldValue::print(ostream &out, bool, - const string &) const { +void AnnotationReferenceFieldValue::print(ostream &out, bool, const string &) const { out << "AnnotationReferenceFieldValue(n)"; } diff --git a/document/src/vespa/document/fieldvalue/arrayfieldvalue.cpp b/document/src/vespa/document/fieldvalue/arrayfieldvalue.cpp index 8c05c25e651..01df81db69b 100644 --- a/document/src/vespa/document/fieldvalue/arrayfieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/arrayfieldvalue.cpp @@ -3,15 +3,23 @@ #include "intfieldvalue.h" #include "stringfieldvalue.h" #include "predicatefieldvalue.h" +#include "iteratorhandler.h" #include <vespa/document/util/serializableexceptions.h> -#include <vespa/vespalib/util/stringfmt.h> +#include <vespa/vespalib/util/polymorphicarrays.h> +#include <vespa/vespalib/util/xmlstream.h> #include <vespa/log/log.h> LOG_SETUP(".document.fieldvalue.array"); +using namespace vespalib::xml; + namespace document { using vespalib::IllegalArgumentException; +using fieldvalue::IndexValue; +using fieldvalue::ModificationStatus; +using fieldvalue::IteratorHandler; +using fieldvalue::VariableMap; IMPLEMENT_IDENTIFIABLE_ABSTRACT(ArrayFieldValue, CollectionFieldValue); @@ -24,7 +32,7 @@ ArrayFieldValue::ArrayFieldValue(const DataType &type) "Cannot generate an array value with non-array type " + type.toString() + ".", VESPA_STRLOC); } - _array = createArray(getNestedType()); + _array.reset(static_cast<IArray *>(createArray(getNestedType()).release())); } ArrayFieldValue::ArrayFieldValue(const ArrayFieldValue& other) @@ -176,14 +184,13 @@ ArrayFieldValue::hasChanged() const return false; } -FieldValue::IteratorHandler::ModificationStatus +fieldvalue::ModificationStatus ArrayFieldValue::iterateSubset(int startPos, int endPos, const vespalib::stringref & variable, PathRange nested, - IteratorHandler& handler) const + fieldvalue::IteratorHandler& handler) const { - FieldValue::IteratorHandler::ModificationStatus - retVal = FieldValue::IteratorHandler::NOT_MODIFIED; + fieldvalue::ModificationStatus retVal = ModificationStatus::NOT_MODIFIED; LOG(spam, "iterateSubset(start=%d, end=%d, variable='%s')", startPos, endPos, variable.c_str()); @@ -192,16 +199,15 @@ ArrayFieldValue::iterateSubset(int startPos, int endPos, for (int i = startPos; i <= endPos && i < static_cast<int>(_array->size()); ++i) { if (!variable.empty()) { - handler.getVariables()[variable] = IteratorHandler::IndexValue(i); + handler.getVariables()[variable] = IndexValue(i); } - FieldValue::IteratorHandler::ModificationStatus - status = array()[i].iterateNested(nested, handler); + ModificationStatus status = array()[i].iterateNested(nested, handler); - if (status == FieldValue::IteratorHandler::REMOVED) { + if (status == ModificationStatus::REMOVED) { indicesToRemove.push_back(i); - retVal = FieldValue::IteratorHandler::MODIFIED; - } else if (status == FieldValue::IteratorHandler::MODIFIED) { + retVal = ModificationStatus::MODIFIED; + } else if (status == ModificationStatus::MODIFIED) { retVal = status; } } @@ -219,7 +225,7 @@ ArrayFieldValue::iterateSubset(int startPos, int endPos, return retVal; } -FieldValue::IteratorHandler::ModificationStatus +fieldvalue::ModificationStatus ArrayFieldValue::onIterateNested(PathRange nested, IteratorHandler & handler) const { IteratorHandler::CollectionScope autoScope(handler, *this); @@ -235,7 +241,7 @@ ArrayFieldValue::onIterateNested(PathRange nested, IteratorHandler & handler) co case FieldPathEntry::VARIABLE: { LOG(spam, "VARIABLE"); - IteratorHandler::VariableMap::iterator iter = handler.getVariables().find(fpe.getVariableName()); + VariableMap::iterator iter = handler.getVariables().find(fpe.getVariableName()); if (iter != handler.getVariables().end()) { int idx = iter->second.index; @@ -259,17 +265,17 @@ ArrayFieldValue::onIterateNested(PathRange nested, IteratorHandler & handler) co } return iterateSubset(0, static_cast<int>(_array->size()) - 1, "", nested, handler); } else { - IteratorHandler::ModificationStatus status = handler.modify(const_cast<ArrayFieldValue&>(*this)); + fieldvalue::ModificationStatus status = handler.modify(const_cast<ArrayFieldValue&>(*this)); - if (status == FieldValue::IteratorHandler::REMOVED) { + if (status == fieldvalue::REMOVED) { return status; } if (handler.handleComplex(*this)) { - if (iterateSubset(0, static_cast<int>(_array->size()) - 1, "", - nested, handler) != FieldValue::IteratorHandler::NOT_MODIFIED) + if (iterateSubset(0, static_cast<int>(_array->size()) - 1, "", nested, handler) + != ModificationStatus::NOT_MODIFIED) { - status = FieldValue::IteratorHandler::MODIFIED; + status = ModificationStatus::MODIFIED; } } diff --git a/document/src/vespa/document/fieldvalue/arrayfieldvalue.h b/document/src/vespa/document/fieldvalue/arrayfieldvalue.h index 33e07e18588..d61acb8605c 100644 --- a/document/src/vespa/document/fieldvalue/arrayfieldvalue.h +++ b/document/src/vespa/document/fieldvalue/arrayfieldvalue.h @@ -14,25 +14,27 @@ #include "collectionfieldvalue.h" #include <vespa/document/datatype/arraydatatype.h> +#include <vespa/vespalib/util/polymorphicarray.h> namespace document { class ArrayFieldValue : public CollectionFieldValue { private: - IArray::UP _array; + using IArray = vespalib::IArrayT<FieldValue>; + std::unique_ptr<IArray> _array; bool addValue(const FieldValue&) override; bool containsValue(const FieldValue& val) const override; bool removeValue(const FieldValue& val) override; - IteratorHandler::ModificationStatus iterateSubset( + fieldvalue::ModificationStatus iterateSubset( int startPos, int endPos, const vespalib::stringref & variable, PathRange nested, - IteratorHandler& handler) const; - IteratorHandler::ModificationStatus onIterateNested(PathRange nested, IteratorHandler & handler) const override; + fieldvalue::IteratorHandler& handler) const; + fieldvalue::ModificationStatus onIterateNested(PathRange nested, fieldvalue::IteratorHandler & handler) const override; public: - typedef IArray::const_iterator const_iterator; - typedef IArray::iterator iterator; - typedef std::unique_ptr<ArrayFieldValue> UP; + using const_iterator = IArray::const_iterator; + using iterator = IArray::iterator; + using UP = std::unique_ptr<ArrayFieldValue>; /** * @param arrayType Type of the array. Must be an ArrayDataType, but does diff --git a/document/src/vespa/document/fieldvalue/document.cpp b/document/src/vespa/document/fieldvalue/document.cpp index 29f487df989..a8336519e16 100644 --- a/document/src/vespa/document/fieldvalue/document.cpp +++ b/document/src/vespa/document/fieldvalue/document.cpp @@ -10,13 +10,14 @@ #include <vespa/document/util/serializableexceptions.h> #include <vespa/document/base/exceptions.h> #include <vespa/document/util/bytebuffer.h> - +#include <vespa/vespalib/util/xmlstream.h> #include <sstream> using vespalib::nbostream; using vespalib::make_string; using vespalib::IllegalArgumentException; using vespalib::IllegalStateException; +using namespace vespalib::xml; namespace document { namespace { diff --git a/document/src/vespa/document/fieldvalue/fieldvalue.cpp b/document/src/vespa/document/fieldvalue/fieldvalue.cpp index 3279eb77a64..c137811514c 100644 --- a/document/src/vespa/document/fieldvalue/fieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/fieldvalue.cpp @@ -10,17 +10,22 @@ #include "doublefieldvalue.h" #include "bytefieldvalue.h" #include "predicatefieldvalue.h" +#include "iteratorhandler.h" #include <vespa/document/util/bytebuffer.h> #include <vespa/document/base/exceptions.h> #include <vespa/document/serialization/vespadocumentserializer.h> #include <vespa/vespalib/objects/nbostream.h> +#include <vespa/vespalib/util/polymorphicarrays.h> +#include <vespa/vespalib/util/xmlstream.h> #include <sstream> using vespalib::FieldBase; using vespalib::nbostream; - +using namespace vespalib::xml; namespace document { +using namespace fieldvalue; + IMPLEMENT_IDENTIFIABLE_ABSTRACT(FieldValue, vespalib::Identifiable); void FieldValue::serialize(nbostream &stream) const { @@ -183,13 +188,13 @@ FieldValue::onGetNestedFieldValue(PathRange nested) const return FieldValue::UP(); } -FieldValue::IteratorHandler::ModificationStatus +ModificationStatus FieldValue::iterateNested(PathRange nested, IteratorHandler & handler) const { return onIterateNested(nested, handler); } -FieldValue::IteratorHandler::ModificationStatus +ModificationStatus FieldValue::onIterateNested(PathRange nested, IteratorHandler & handler) const { if (nested.atEnd()) { @@ -200,78 +205,6 @@ FieldValue::onIterateNested(PathRange nested, IteratorHandler & handler) const } } -FieldValue::IteratorHandler::~IteratorHandler() { } - -bool -FieldValue::IteratorHandler::IndexValue::operator==(const FieldValue::IteratorHandler::IndexValue& other) const { - if (key.get() != NULL) { - if (other.key.get() != NULL && *key == *other.key) { - return true; - } - return false; - } - - return index == other.index; -} - -FieldValue::IteratorHandler::IndexValue::IndexValue(const FieldValue& key_) - : index(-1), - key(FieldValue::CP(key_.clone())) -{ } - -FieldValue::IteratorHandler::IndexValue::~IndexValue() { } - -vespalib::string -FieldValue::IteratorHandler::IndexValue::toString() const { - if (key.get() != NULL) { - return key->toString(); - } else { - return vespalib::make_string("%d", index); - } -} - -void -FieldValue::IteratorHandler::handlePrimitive(uint32_t fid, const FieldValue & fv) { - onPrimitive(fid, Content(fv, getWeight())); -} -bool -FieldValue::IteratorHandler::handleComplex(const FieldValue & fv) { - return onComplex(Content(fv, getWeight())); -} -void -FieldValue::IteratorHandler::handleCollectionStart(const FieldValue & fv) { - onCollectionStart(Content(fv, getWeight())); -} -void -FieldValue::IteratorHandler::handleCollectionEnd(const FieldValue & fv) { - onCollectionEnd(Content(fv, getWeight())); -} -void -FieldValue::IteratorHandler::handleStructStart(const FieldValue & fv) { - onStructStart(Content(fv, getWeight())); -} -void -FieldValue::IteratorHandler::handleStructEnd(const FieldValue & fv) { - onStructEnd(Content(fv, getWeight())); -} - -void -FieldValue::IteratorHandler::onPrimitive(uint32_t fid, const Content & fv) { - (void) fid; - (void) fv; -} - -std::string -FieldValue::IteratorHandler::toString(const VariableMap& vars) { - std::ostringstream out; - out << "[ "; - for (const auto & entry : vars) { - out << entry.first << "=" << entry.second.toString() << " "; - } - out << "]"; - return out.str(); -} - std::string FieldValue::toString(bool verbose, const std::string& indent) const { @@ -295,26 +228,26 @@ private: }; } -FieldValue::IArray::UP +std::unique_ptr<vespalib::IArrayBase> FieldValue::createArray(const DataType & baseType) { switch(baseType.getId()) { case DataType::T_INT: - return IArray::UP(new PrimitiveArrayT<IntFieldValue, FieldValue>()); + return std::make_unique<PrimitiveArrayT<IntFieldValue, FieldValue>>(); case DataType::T_FLOAT: - return IArray::UP(new PrimitiveArrayT<FloatFieldValue, FieldValue>()); + return std::make_unique<PrimitiveArrayT<FloatFieldValue, FieldValue>>(); case DataType::T_STRING: - return IArray::UP(new PrimitiveArrayT<StringFieldValue, FieldValue>()); + return std::make_unique<PrimitiveArrayT<StringFieldValue, FieldValue>>(); case DataType::T_RAW: - return IArray::UP(new PrimitiveArrayT<RawFieldValue, FieldValue>()); + return std::make_unique<PrimitiveArrayT<RawFieldValue, FieldValue>>(); case DataType::T_LONG: - return IArray::UP(new PrimitiveArrayT<LongFieldValue, FieldValue>()); + return std::make_unique<PrimitiveArrayT<LongFieldValue, FieldValue>>(); case DataType::T_DOUBLE: - return IArray::UP(new PrimitiveArrayT<DoubleFieldValue, FieldValue>()); + return std::make_unique<PrimitiveArrayT<DoubleFieldValue, FieldValue>>(); case DataType::T_BYTE: - return IArray::UP(new PrimitiveArrayT<ByteFieldValue, FieldValue>()); + return std::make_unique<PrimitiveArrayT<ByteFieldValue, FieldValue>>(); default: - return IArray::UP(new ComplexArrayT<FieldValue>(FieldValueFactory::UP(new FieldValueFactory(DataType::UP(baseType.clone()))))); + return std::make_unique<ComplexArrayT<FieldValue>>(std::make_unique<FieldValueFactory>(DataType::UP(baseType.clone()))); } } diff --git a/document/src/vespa/document/fieldvalue/fieldvalue.h b/document/src/vespa/document/fieldvalue/fieldvalue.h index 998673ddf8d..a96628514c3 100644 --- a/document/src/vespa/document/fieldvalue/fieldvalue.h +++ b/document/src/vespa/document/fieldvalue/fieldvalue.h @@ -12,12 +12,12 @@ #pragma once #include "fieldvaluevisitor.h" +#include "modificationstatus.h" #include <vespa/document/util/xmlserializable.h> -#include <vespa/vespalib/util/polymorphicarrays.h> +#include <vespa/document/base/fieldpath.h> #include <vespa/vespalib/objects/cloneable.h> #include <vespa/vespalib/objects/identifiable.h> -#include <vespa/document/base/fieldpath.h> -#include <map> +#include <vespa/vespalib/util/polymorphicarraybase.h> namespace vespalib { class nbostream; @@ -25,6 +25,10 @@ namespace vespalib { namespace document { +namespace fieldvalue { + class IteratorHandler; +} + class ByteBuffer; class DataType; @@ -33,8 +37,7 @@ class FieldValue : public vespalib::Identifiable protected: FieldValue(const FieldValue&) = default; FieldValue& operator=(const FieldValue&) = default; - using IArray = vespalib::IArrayT<FieldValue>; - static IArray::UP createArray(const DataType & baseType); + static std::unique_ptr<vespalib::IArrayBase> createArray(const DataType & baseType); public: using PathRange = FieldPath::Range<FieldPath::const_iterator>; @@ -42,110 +45,6 @@ public: using SP = std::shared_ptr<FieldValue>; using CP = vespalib::CloneablePtr<FieldValue>; - class IteratorHandler { - public: - class CollectionScope { - public: - CollectionScope(IteratorHandler& handler, const FieldValue& value) - : _handler(handler), _value(value) - { - _handler.handleCollectionStart(_value); - } - - ~CollectionScope() { - _handler.handleCollectionEnd(_value); - } - private: - IteratorHandler& _handler; - const FieldValue& _value; - }; - - class StructScope { - public: - StructScope(IteratorHandler& handler, const FieldValue& value) - : _handler(handler), _value(value) - { - _handler.handleStructStart(_value); - } - - ~StructScope() { - _handler.handleStructEnd(_value); - } - private: - IteratorHandler& _handler; - const FieldValue& _value; - }; - - class IndexValue { - public: - IndexValue() : index(-1), key() {} - IndexValue(int index_) : index(index_), key() {} - IndexValue(const FieldValue& key_); - ~IndexValue(); - - vespalib::string toString() const; - - bool operator==(const IndexValue& other) const; - - int index; // For array - FieldValue::CP key; // For map/wset - }; - - enum ModificationStatus { - MODIFIED, - REMOVED, - NOT_MODIFIED - }; - - typedef std::map<vespalib::string, IndexValue> VariableMap; - protected: - class Content { - public: - Content(const FieldValue & fv, int weight=1) : _fieldValue(fv), _weight(weight) { } - int getWeight() const { return _weight; } - const FieldValue & getValue() const { return _fieldValue; } - private: - const FieldValue & _fieldValue; - int _weight; - }; - IteratorHandler() : _weight(1) { } - public: - virtual ~IteratorHandler(); - - void handlePrimitive(uint32_t fid, const FieldValue & fv); - - /** - Handles a complex type (struct/array/map etc) that is at the end of the - field path. - @return Return true if you want to recurse into the members. - */ - bool handleComplex(const FieldValue& fv); - void handleCollectionStart(const FieldValue & fv); - void handleCollectionEnd(const FieldValue & fv); - void handleStructStart(const FieldValue & fv); - void handleStructEnd(const FieldValue & fv); - void setWeight(int weight) { _weight = weight; } - ModificationStatus modify(FieldValue& fv) { return doModify(fv); } - - VariableMap& getVariables() { return _variables; } - void setVariables(const VariableMap& vars) { _variables = vars; } - static std::string toString(const VariableMap& vars); - virtual bool createMissingPath() const { return false; } - private: - virtual bool onComplex(const Content& fv) { (void) fv; return true; } - virtual void onPrimitive(uint32_t fid, const Content & fv); - virtual void onCollectionStart(const Content & fv) { (void) fv; } - virtual void onCollectionEnd(const Content & fv) { (void) fv; } - virtual void onStructStart(const Content & fv) { (void) fv; } - virtual void onStructEnd(const Content & fv) { (void) fv; } - virtual ModificationStatus doModify(FieldValue&) { return NOT_MODIFIED; }; - - // Scratchpad to store pass on weight. - int getWeight() const { return _weight; } - int _weight; - VariableMap _variables; - }; - DECLARE_IDENTIFIABLE_ABSTRACT(FieldValue); FieldValue() {} @@ -270,9 +169,9 @@ public: * invocations of the before mentioned methods and the additional * onPrimitive. */ - IteratorHandler::ModificationStatus iterateNested(PathRange nested, IteratorHandler & handler) const; + fieldvalue::ModificationStatus iterateNested(PathRange nested, fieldvalue::IteratorHandler & handler) const; - IteratorHandler::ModificationStatus iterateNested(const FieldPath& fieldPath, IteratorHandler& handler) const { + fieldvalue::ModificationStatus iterateNested(const FieldPath& fieldPath, fieldvalue::IteratorHandler& handler) const { return iterateNested(fieldPath.begin(), fieldPath.end(), handler); } @@ -286,12 +185,12 @@ public: virtual void printXml(XmlOutputStream& out) const = 0; private: - IteratorHandler::ModificationStatus - iterateNested(FieldPath::const_iterator start, FieldPath::const_iterator end, IteratorHandler & handler) const { + fieldvalue::ModificationStatus + iterateNested(FieldPath::const_iterator start, FieldPath::const_iterator end, fieldvalue::IteratorHandler & handler) const { return iterateNested(PathRange(start, end), handler); } virtual FieldValue::UP onGetNestedFieldValue(PathRange nested) const; - virtual IteratorHandler::ModificationStatus onIterateNested(PathRange nested, IteratorHandler & handler) const; + virtual fieldvalue::ModificationStatus onIterateNested(PathRange nested, fieldvalue::IteratorHandler & handler) const; }; std::ostream& operator<<(std::ostream& out, const FieldValue & p); diff --git a/document/src/vespa/document/fieldvalue/iteratorhandler.cpp b/document/src/vespa/document/fieldvalue/iteratorhandler.cpp new file mode 100644 index 00000000000..394979f31cb --- /dev/null +++ b/document/src/vespa/document/fieldvalue/iteratorhandler.cpp @@ -0,0 +1,43 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + + +#include "iteratorhandler.h" + +namespace document::fieldvalue { + +IteratorHandler::~IteratorHandler() { } + + +void +IteratorHandler::handlePrimitive(uint32_t fid, const FieldValue & fv) { + onPrimitive(fid, Content(fv, getWeight())); +} +bool +IteratorHandler::handleComplex(const FieldValue & fv) { + return onComplex(Content(fv, getWeight())); +} +void +IteratorHandler::handleCollectionStart(const FieldValue & fv) { + onCollectionStart(Content(fv, getWeight())); +} +void +IteratorHandler::handleCollectionEnd(const FieldValue & fv) { + onCollectionEnd(Content(fv, getWeight())); +} +void +IteratorHandler::handleStructStart(const FieldValue & fv) { + onStructStart(Content(fv, getWeight())); +} +void +IteratorHandler::handleStructEnd(const FieldValue & fv) { + onStructEnd(Content(fv, getWeight())); +} + +void +IteratorHandler::onPrimitive(uint32_t fid, const Content & fv) { + (void) fid; + (void) fv; +} + +} + diff --git a/document/src/vespa/document/fieldvalue/iteratorhandler.h b/document/src/vespa/document/fieldvalue/iteratorhandler.h new file mode 100644 index 00000000000..8dc98b2107d --- /dev/null +++ b/document/src/vespa/document/fieldvalue/iteratorhandler.h @@ -0,0 +1,99 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include "variablemap.h" +#include "modificationstatus.h" + +namespace document::fieldvalue { + +class IteratorHandler { +public: + class CollectionScope { + public: + CollectionScope(IteratorHandler &handler, const FieldValue &value) + : _handler(handler), _value(value) { + _handler.handleCollectionStart(_value); + } + + ~CollectionScope() { + _handler.handleCollectionEnd(_value); + } + + private: + IteratorHandler &_handler; + const FieldValue &_value; + }; + + class StructScope { + public: + StructScope(IteratorHandler &handler, const FieldValue &value) + : _handler(handler), _value(value) { + _handler.handleStructStart(_value); + } + + ~StructScope() { + _handler.handleStructEnd(_value); + } + + private: + IteratorHandler &_handler; + const FieldValue &_value; + }; + +protected: + class Content { + public: + Content(const FieldValue &fv, int weight = 1) : _fieldValue(fv), _weight(weight) {} + + int getWeight() const { return _weight; } + + const FieldValue &getValue() const { return _fieldValue; } + + private: + const FieldValue &_fieldValue; + int _weight; + }; + + IteratorHandler() : _weight(1) {} + +public: + virtual ~IteratorHandler(); + void handlePrimitive(uint32_t fid, const FieldValue &fv); + + /** + Handles a complex type (struct/array/map etc) that is at the end of the + field path. + @return Return true if you want to recurse into the members. + */ + bool handleComplex(const FieldValue &fv); + void handleCollectionStart(const FieldValue &fv); + void handleCollectionEnd(const FieldValue &fv); + void handleStructStart(const FieldValue &fv); + void handleStructEnd(const FieldValue &fv); + void setWeight(int weight) { _weight = weight; } + ModificationStatus modify(FieldValue &fv) { return doModify(fv); } + fieldvalue::VariableMap &getVariables() { return _variables; } + void setVariables(const fieldvalue::VariableMap &vars) { _variables = vars; } + virtual bool createMissingPath() const { return false; } +private: + virtual bool onComplex(const Content &fv) { + (void) fv; + return true; + } + + virtual void onPrimitive(uint32_t fid, const Content &fv); + virtual void onCollectionStart(const Content &fv) { (void) fv; } + virtual void onCollectionEnd(const Content &fv) { (void) fv; } + virtual void onStructStart(const Content &fv) { (void) fv; } + virtual void onStructEnd(const Content &fv) { (void) fv; } + virtual ModificationStatus doModify(FieldValue &) { return NOT_MODIFIED; }; + + // Scratchpad to store pass on weight. + int getWeight() const { return _weight; } + + int _weight; + fieldvalue::VariableMap _variables; +}; + +} diff --git a/document/src/vespa/document/fieldvalue/literalfieldvalue.cpp b/document/src/vespa/document/fieldvalue/literalfieldvalue.cpp index 4d044219d4c..50c6c901808 100644 --- a/document/src/vespa/document/fieldvalue/literalfieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/literalfieldvalue.cpp @@ -1,9 +1,12 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/document/fieldvalue/literalfieldvalue.h> +#include "literalfieldvalue.h" #include <vespa/document/util/stringutil.h> +#include <vespa/vespalib/util/xmlstream.h> #include <sstream> +using namespace vespalib::xml; + namespace document { IMPLEMENT_IDENTIFIABLE_ABSTRACT(LiteralFieldValueB, FieldValue); diff --git a/document/src/vespa/document/fieldvalue/mapfieldvalue.cpp b/document/src/vespa/document/fieldvalue/mapfieldvalue.cpp index 2186ff28f60..a2bc5b97299 100644 --- a/document/src/vespa/document/fieldvalue/mapfieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/mapfieldvalue.cpp @@ -2,12 +2,15 @@ #include "mapfieldvalue.h" #include "weightedsetfieldvalue.h" +#include "iteratorhandler.h" #include <vespa/document/base/exceptions.h> +#include <vespa/vespalib/util/xmlstream.h> #include <vespa/log/log.h> LOG_SETUP(".document.fieldvalue.map"); using vespalib::Identifiable; +using namespace vespalib::xml; /// \todo TODO (was warning): // Find a way to search through internal map without @@ -15,6 +18,8 @@ using vespalib::Identifiable; namespace document { +using namespace fieldvalue; + IMPLEMENT_IDENTIFIABLE_ABSTRACT(MapFieldValue, FieldValue); namespace { @@ -31,8 +36,8 @@ const MapDataType *verifyMapType(const DataType& type) { MapFieldValue::MapFieldValue(const DataType &mapType) : FieldValue(), _type(verifyMapType(mapType)), - _keys(createArray(getMapType().getKeyType())), - _values(createArray(getMapType().getValueType())), + _keys(static_cast<IArray *>(createArray(getMapType().getKeyType()).release())), + _values(static_cast<IArray *>(createArray(getMapType().getValueType()).release())), _altered(true) { } @@ -268,22 +273,22 @@ MapFieldValue::find(const FieldValue& key) } bool MapFieldValue::checkAndRemove(const FieldValue& key, - FieldValue::IteratorHandler::ModificationStatus status, + ModificationStatus status, bool wasModified, std::vector<const FieldValue*>& keysToRemove) const { - if (status == FieldValue::IteratorHandler::REMOVED) { + if (status == ModificationStatus::REMOVED) { LOG(spam, "will remove: %s", key.toString().c_str()); keysToRemove.push_back(&key); return true; - } else if (status == FieldValue::IteratorHandler::MODIFIED) { + } else if (status == ModificationStatus::MODIFIED) { return true; } return wasModified; } -FieldValue::IteratorHandler::ModificationStatus +ModificationStatus MapFieldValue::iterateNestedImpl(PathRange nested, IteratorHandler & handler, const FieldValue& complexFieldValue) const @@ -307,10 +312,9 @@ MapFieldValue::iterateNestedImpl(PathRange nested, wasModified, keysToRemove); } else if (handler.createMissingPath()) { LOG(spam, "creating missing path"); - FieldValue::UP val = - getMapType().getValueType().createFieldValue(); - IteratorHandler::ModificationStatus status = val->iterateNested(nested.next(), handler); - if (status == IteratorHandler::MODIFIED) { + FieldValue::UP val = getMapType().getValueType().createFieldValue(); + ModificationStatus status = val->iterateNested(nested.next(), handler); + if (status == ModificationStatus::MODIFIED) { const_cast<MapFieldValue&>(*this).put(FieldValue::UP(fpe.getLookupKey()->clone()), std::move(val)); return status; } @@ -339,8 +343,7 @@ MapFieldValue::iterateNestedImpl(PathRange nested, case FieldPathEntry::VARIABLE: { LOG(spam, "VARIABLE"); - IteratorHandler::VariableMap::iterator - iter = handler.getVariables().find(fpe.getVariableName()); + VariableMap::iterator iter = handler.getVariables().find(fpe.getVariableName()); if (iter != handler.getVariables().end()) { LOG(spam, "variable key = %s", iter->second.key->toString().c_str()); const_iterator found = find(*iter->second.key); @@ -353,12 +356,9 @@ MapFieldValue::iterateNestedImpl(PathRange nested, PathRange next = nested.next(); for (const_iterator it(begin()), mt(end()); it != mt; it++) { LOG(spam, "key is '%s'", it->first->toString().c_str()); - handler.getVariables()[fpe.getVariableName()] - = IteratorHandler::IndexValue(*it->first); - LOG(spam, "vars at this time = %s", - FieldValue::IteratorHandler::toString(handler.getVariables()).c_str()); - wasModified = checkAndRemove(*it->first, - it->second->iterateNested(next, handler), + handler.getVariables()[fpe.getVariableName()] = IndexValue(*it->first); + LOG(spam, "vars at this time = %s", handler.getVariables().toString().c_str()); + wasModified = checkAndRemove(*it->first, it->second->iterateNested(next, handler), wasModified, keysToRemove); } handler.getVariables().erase(fpe.getVariableName()); @@ -371,8 +371,7 @@ MapFieldValue::iterateNestedImpl(PathRange nested, if (isWSet) { handler.setWeight(static_cast<const IntFieldValue &>(*it->second).getValue()); } - wasModified = checkAndRemove(*it->first, - it->first->iterateNested(nested, handler), + wasModified = checkAndRemove(*it->first, it->first->iterateNested(nested, handler), wasModified, keysToRemove); // Don't iterate over values /*wasModified = checkAndRemove(*it->second, @@ -383,13 +382,12 @@ MapFieldValue::iterateNestedImpl(PathRange nested, } } else { LOG(spam, "at end of field path"); - IteratorHandler::ModificationStatus - status = handler.modify(const_cast<FieldValue&>(complexFieldValue)); + ModificationStatus status = handler.modify(const_cast<FieldValue&>(complexFieldValue)); - if (status == IteratorHandler::REMOVED) { + if (status == ModificationStatus::REMOVED) { LOG(spam, "status = REMOVED"); return status; - } else if (status == IteratorHandler::MODIFIED) { + } else if (status == ModificationStatus::MODIFIED) { LOG(spam, "status = MODIFIED"); wasModified = true; } @@ -419,10 +417,10 @@ MapFieldValue::iterateNestedImpl(PathRange nested, LOG(spam, "erasing map entry with key %s", (*i)->toString().c_str()); const_cast<MapFieldValue&>(*this).erase(**i); } - return wasModified ? IteratorHandler::MODIFIED : IteratorHandler::NOT_MODIFIED; + return wasModified ? ModificationStatus::MODIFIED : ModificationStatus::NOT_MODIFIED; } -FieldValue::IteratorHandler::ModificationStatus +ModificationStatus MapFieldValue::onIterateNested(PathRange nested, IteratorHandler & handler) const { LOG(spam, "iterating over MapFieldValue"); diff --git a/document/src/vespa/document/fieldvalue/mapfieldvalue.h b/document/src/vespa/document/fieldvalue/mapfieldvalue.h index 8b480cbb7f9..edc20fea777 100644 --- a/document/src/vespa/document/fieldvalue/mapfieldvalue.h +++ b/document/src/vespa/document/fieldvalue/mapfieldvalue.h @@ -26,10 +26,10 @@ private: virtual bool containsValue(const FieldValue& fv) const { return contains(fv); } virtual bool removeValue(const FieldValue& fv) { return erase(fv); } bool checkAndRemove(const FieldValue& key, - FieldValue::IteratorHandler::ModificationStatus status, + fieldvalue::ModificationStatus status, bool wasModified, std::vector<const FieldValue*>& keysToRemove) const; - IteratorHandler::ModificationStatus onIterateNested(PathRange nested, IteratorHandler & handler) const override; + fieldvalue::ModificationStatus onIterateNested(PathRange nested, fieldvalue::IteratorHandler & handler) const override; // Utility method to avoid constant explicit casting const MapDataType& getMapType() const { return *_type; } @@ -118,8 +118,8 @@ public: void reserve(size_t sz) { _keys->reserve(sz); _values->reserve(sz); } void resize(size_t sz) { _keys->resize(sz); _values->resize(sz); } - IteratorHandler::ModificationStatus iterateNestedImpl(PathRange nested, IteratorHandler & handler, - const FieldValue& complexFieldValue) const; + fieldvalue::ModificationStatus iterateNestedImpl(PathRange nested, fieldvalue::IteratorHandler & handler, + const FieldValue& complexFieldValue) const; // FieldValue implementation FieldValue& assign(const FieldValue&) override; diff --git a/document/src/vespa/document/fieldvalue/modificationstatus.h b/document/src/vespa/document/fieldvalue/modificationstatus.h new file mode 100644 index 00000000000..344a89338bb --- /dev/null +++ b/document/src/vespa/document/fieldvalue/modificationstatus.h @@ -0,0 +1,13 @@ +// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +namespace document::fieldvalue { + +enum ModificationStatus { + MODIFIED, + REMOVED, + NOT_MODIFIED +}; + +} diff --git a/document/src/vespa/document/fieldvalue/numericfieldvalue.cpp b/document/src/vespa/document/fieldvalue/numericfieldvalue.cpp index 3d39544b3d0..b897a8db930 100644 --- a/document/src/vespa/document/fieldvalue/numericfieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/numericfieldvalue.cpp @@ -1,6 +1,7 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "numericfieldvalue.h" +#include <vespa/vespalib/util/xmlstream.h> namespace document { @@ -9,7 +10,7 @@ IMPLEMENT_IDENTIFIABLE_ABSTRACT(NumericFieldValueBase, FieldValue); void NumericFieldValueBase::printXml(XmlOutputStream& out) const { - out << XmlContent(getAsString()); + out << vespalib::xml::XmlContent(getAsString()); } diff --git a/document/src/vespa/document/fieldvalue/predicatefieldvalue.cpp b/document/src/vespa/document/fieldvalue/predicatefieldvalue.cpp index 8e963f75f5d..a3394d8fcf4 100644 --- a/document/src/vespa/document/fieldvalue/predicatefieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/predicatefieldvalue.cpp @@ -6,9 +6,11 @@ #include <vespa/document/predicate/predicate_printer.h> #include <vespa/vespalib/data/slime/inserter.h> #include <vespa/vespalib/data/slime/slime.h> +#include <vespa/vespalib/util/xmlstream.h> using vespalib::Slime; using vespalib::slime::SlimeInserter; +using namespace vespalib::xml; namespace document { diff --git a/document/src/vespa/document/fieldvalue/rawfieldvalue.cpp b/document/src/vespa/document/fieldvalue/rawfieldvalue.cpp index 96701832b5e..c9950036435 100644 --- a/document/src/vespa/document/fieldvalue/rawfieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/rawfieldvalue.cpp @@ -3,6 +3,9 @@ #include "rawfieldvalue.h" #include "literalfieldvalue.hpp" #include <vespa/document/util/stringutil.h> +#include <vespa/vespalib/util/xmlstream.h> + +using namespace vespalib::xml; namespace document { @@ -18,8 +21,7 @@ RawFieldValue::printXml(XmlOutputStream& out) const void RawFieldValue::print(std::ostream& out, bool, const std::string&) const { - StringUtil::printAsHex(out, _value.c_str(), - _value.size()); + StringUtil::printAsHex(out, _value.c_str(), _value.size()); } } // document diff --git a/document/src/vespa/document/fieldvalue/structfieldvalue.cpp b/document/src/vespa/document/fieldvalue/structfieldvalue.cpp index 74805ce3f10..cdfba106c49 100644 --- a/document/src/vespa/document/fieldvalue/structfieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/structfieldvalue.cpp @@ -11,6 +11,7 @@ #include <vespa/document/util/serializableexceptions.h> #include <vespa/document/base/exceptions.h> #include <vespa/document/util/bytebuffer.h> +#include <vespa/vespalib/util/xmlstream.h> #include <vespa/log/log.h> LOG_SETUP(".document.structfieldvalue"); @@ -19,6 +20,7 @@ using std::vector; using vespalib::nbostream; using vespalib::nbostream_longlivedbuf; using vespalib::make_string; +using namespace vespalib::xml; namespace document { diff --git a/document/src/vespa/document/fieldvalue/structuredfieldvalue.cpp b/document/src/vespa/document/fieldvalue/structuredfieldvalue.cpp index 6d77d101ff2..beef80ed2b0 100644 --- a/document/src/vespa/document/fieldvalue/structuredfieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/structuredfieldvalue.cpp @@ -1,13 +1,19 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "structuredfieldvalue.hpp" -#include "fieldvalues.h" +#include "iteratorhandler.h" +#include "weightedsetfieldvalue.h" +#include "arrayfieldvalue.h" #include <vespa/log/log.h> LOG_SETUP(".document.fieldvalue.structured"); +using vespalib::IllegalArgumentException; + namespace document { +using namespace fieldvalue; + IMPLEMENT_IDENTIFIABLE_ABSTRACT(StructuredFieldValue, FieldValue); StructuredFieldValue::Iterator::Iterator() @@ -59,7 +65,7 @@ void StructuredFieldValue::setFieldValue(const Field & field, const FieldValue & if (!field.getDataType().isValueType(value) && !value.getDataType()->isA(field.getDataType())) { - throw vespalib::IllegalArgumentException( + throw IllegalArgumentException( "Cannot assign value of type " + value.getDataType()->toString() + "with value : '" + value.toString() + "' to field " + field.getName().c_str() + " of type " @@ -81,7 +87,7 @@ StructuredFieldValue::onGetNestedFieldValue(PathRange nested) const return fv; } -FieldValue::IteratorHandler::ModificationStatus +ModificationStatus StructuredFieldValue::onIterateNested(PathRange nested, IteratorHandler & handler) const { IteratorHandler::StructScope autoScope(handler, *this); @@ -93,38 +99,36 @@ StructuredFieldValue::onIterateNested(PathRange nested, IteratorHandler & handle LOG(spam, "fieldRef = %s", fpe.getFieldRef().toString().c_str()); LOG(spam, "fieldValueToSet = %s", fpe.getFieldValueToSet().toString().c_str()); if (exists) { - IteratorHandler::ModificationStatus status = fpe.getFieldValueToSet().iterateNested(nested.next(), handler); - if (status == IteratorHandler::REMOVED) { + ModificationStatus status = fpe.getFieldValueToSet().iterateNested(nested.next(), handler); + if (status == ModificationStatus::REMOVED) { LOG(spam, "field exists, status = REMOVED"); const_cast<StructuredFieldValue&>(*this).remove(fpe.getFieldRef()); - return IteratorHandler::MODIFIED; - } else if (status == IteratorHandler::MODIFIED) { + return ModificationStatus::MODIFIED; + } else if (status == ModificationStatus::MODIFIED) { LOG(spam, "field exists, status = MODIFIED"); const_cast<StructuredFieldValue&>(*this).setFieldValue(fpe.getFieldRef(), fpe.getFieldValueToSet()); - return IteratorHandler::MODIFIED; + return ModificationStatus::MODIFIED; } else { LOG(spam, "field exists, status = %u", status); return status; } } else if (handler.createMissingPath()) { LOG(spam, "createMissingPath is true"); - IteratorHandler::ModificationStatus status - = fpe.getFieldValueToSet().iterateNested(nested.next(), handler); - if (status == IteratorHandler::MODIFIED) { + ModificationStatus status = fpe.getFieldValueToSet().iterateNested(nested.next(), handler); + if (status == ModificationStatus::MODIFIED) { LOG(spam, "field did not exist, status = MODIFIED"); const_cast<StructuredFieldValue&>(*this).setFieldValue(fpe.getFieldRef(), fpe.getFieldValueToSet()); return status; } } LOG(spam, "field did not exist, returning NOT_MODIFIED"); - return IteratorHandler::NOT_MODIFIED; + return ModificationStatus ::NOT_MODIFIED; } else { - throw vespalib::IllegalArgumentException("Illegal field path for struct value"); + throw IllegalArgumentException("Illegal field path for struct value"); } } else { - IteratorHandler::ModificationStatus - status = handler.modify(const_cast<StructuredFieldValue&>(*this)); - if (status == IteratorHandler::REMOVED) { + ModificationStatus status = handler.modify(const_cast<StructuredFieldValue&>(*this)); + if (status == ModificationStatus::REMOVED) { LOG(spam, "field REMOVED"); return status; } @@ -133,11 +137,11 @@ StructuredFieldValue::onIterateNested(PathRange nested, IteratorHandler & handle LOG(spam, "handleComplex"); std::vector<const Field*> fieldsToRemove; for (const_iterator it(begin()), mt(end()); it != mt; ++it) { - IteratorHandler::ModificationStatus currStatus = getValue(it.field())->iterateNested(nested, handler); - if (currStatus == IteratorHandler::REMOVED) { + ModificationStatus currStatus = getValue(it.field())->iterateNested(nested, handler); + if (currStatus == ModificationStatus::REMOVED) { fieldsToRemove.push_back(&it.field()); - status = IteratorHandler::MODIFIED; - } else if (currStatus == IteratorHandler::MODIFIED) { + status = ModificationStatus::MODIFIED; + } else if (currStatus == ModificationStatus::MODIFIED) { status = currStatus; } } diff --git a/document/src/vespa/document/fieldvalue/structuredfieldvalue.h b/document/src/vespa/document/fieldvalue/structuredfieldvalue.h index 4cccbf05de0..eb5912734c5 100644 --- a/document/src/vespa/document/fieldvalue/structuredfieldvalue.h +++ b/document/src/vespa/document/fieldvalue/structuredfieldvalue.h @@ -92,8 +92,8 @@ protected: virtual void setFieldValue(const Field&, FieldValue::UP value) = 0; void setFieldValue(const Field & field, const FieldValue & value); - IteratorHandler::ModificationStatus - onIterateNested(PathRange nested, IteratorHandler & handler) const override; + fieldvalue::ModificationStatus + onIterateNested(PathRange nested, fieldvalue::IteratorHandler & handler) const override; public: DECLARE_IDENTIFIABLE_ABSTRACT(StructuredFieldValue); diff --git a/document/src/vespa/document/fieldvalue/tensorfieldvalue.cpp b/document/src/vespa/document/fieldvalue/tensorfieldvalue.cpp index 93ec934968d..d7d7721e833 100644 --- a/document/src/vespa/document/fieldvalue/tensorfieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/tensorfieldvalue.cpp @@ -2,11 +2,13 @@ #include "tensorfieldvalue.h" #include <vespa/document/datatype/datatype.h> +#include <vespa/vespalib/util/xmlstream.h> #include <vespa/eval/tensor/tensor.h> #include <ostream> #include <cassert> using vespalib::tensor::Tensor; +using namespace vespalib::xml; namespace document { diff --git a/document/src/vespa/document/fieldvalue/variablemap.cpp b/document/src/vespa/document/fieldvalue/variablemap.cpp new file mode 100644 index 00000000000..b38b5baeec2 --- /dev/null +++ b/document/src/vespa/document/fieldvalue/variablemap.cpp @@ -0,0 +1,59 @@ +#include "variablemap.h" +#include "fieldvalue.h" +#include <vespa/vespalib/util/stringfmt.h> +#include <vespa/vespalib/stllike/asciistream.h> + +namespace document::fieldvalue { + +IndexValue::IndexValue() : index(-1), key() {} +IndexValue::IndexValue(int index_) : index(index_), key() {} + +bool +IndexValue::operator==(const IndexValue& other) const { + if (key.get() != NULL) { + if (other.key.get() != NULL && *key == *other.key) { + return true; + } + return false; + } + + return index == other.index; +} + +IndexValue::IndexValue(const FieldValue& key_) + : index(-1), + key(FieldValue::CP(key_.clone())) +{ } + +IndexValue::IndexValue(const IndexValue & rhs) = default; +IndexValue & IndexValue::operator = (const IndexValue & rhs) = default; + +IndexValue::~IndexValue() { } + +vespalib::string +IndexValue::toString() const { + if (key.get() != NULL) { + return key->toString(); + } else { + return vespalib::make_string("%d", index); + } +} + +VariableMap::VariableMap() {} +VariableMap::~VariableMap() {} +VariableMap::VariableMap(const VariableMap & rhs) = default; +VariableMap & VariableMap::operator = (const VariableMap & rhs) = default; + +vespalib::string +VariableMap::toString() const { + vespalib::asciistream out; + out << "[ "; + for (const auto & entry : *this) { + out << entry.first << "=" << entry.second.toString() << " "; + } + out << "]"; + return out.str(); +} + +} + diff --git a/document/src/vespa/document/fieldvalue/variablemap.h b/document/src/vespa/document/fieldvalue/variablemap.h new file mode 100644 index 00000000000..06679682e0c --- /dev/null +++ b/document/src/vespa/document/fieldvalue/variablemap.h @@ -0,0 +1,47 @@ +// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include <vespa/vespalib/util/memory.h> +#include <vespa/vespalib/stllike/string.h> +#include <map> + +namespace document { + class FieldValue; +} + +namespace document::fieldvalue { + +class IndexValue { +public: + IndexValue(); + IndexValue(int index_); + IndexValue(const FieldValue& key_); + IndexValue(IndexValue && rhs) = default; + IndexValue & operator = (IndexValue && rhs) = default; + IndexValue(const IndexValue & rhs); + IndexValue & operator = (const IndexValue & rhs); + + ~IndexValue(); + + vespalib::string toString() const; + bool operator==(const IndexValue& other) const; + + int index; // For array + vespalib::CloneablePtr<FieldValue> key; // For map/wset +}; + +using VariableMapT = std::map<vespalib::string, IndexValue>; + +class VariableMap : public VariableMapT { +public: + VariableMap(); + VariableMap(VariableMap && rhs) = default; + VariableMap & operator = (VariableMap && rhs) = default; + VariableMap(const VariableMap & rhs); + VariableMap & operator = (const VariableMap & rhs); + ~VariableMap(); + vespalib::string toString() const; +}; + +}
\ No newline at end of file diff --git a/document/src/vespa/document/fieldvalue/weightedsetfieldvalue.cpp b/document/src/vespa/document/fieldvalue/weightedsetfieldvalue.cpp index 7bf5f5350d3..67e0c8327e6 100644 --- a/document/src/vespa/document/fieldvalue/weightedsetfieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/weightedsetfieldvalue.cpp @@ -2,14 +2,20 @@ #include "weightedsetfieldvalue.h" #include <vespa/document/base/exceptions.h> +#include <vespa/vespalib/util/xmlstream.h> #include <ostream> using vespalib::Identifiable; +using vespalib::IllegalArgumentException; +using vespalib::IllegalStateException; +using namespace vespalib::xml; /// \todo TODO (was warning): Find a way to search through internal map without duplicating keys to create shared pointers. namespace document { +using namespace fieldvalue; + IMPLEMENT_IDENTIFIABLE_ABSTRACT(WeightedSetFieldValue, CollectionFieldValue); namespace { @@ -17,9 +23,8 @@ const DataType &getKeyType(const DataType &type) { const WeightedSetDataType *wtype = Identifiable::cast<const WeightedSetDataType *>(&type); if (!wtype) { - throw vespalib::IllegalArgumentException( - "Cannot generate a weighted set value with non-weighted set " - "type " + type.toString() + ".", VESPA_STRLOC); + throw IllegalArgumentException("Cannot generate a weighted set value with non-weighted set " + "type " + type.toString() + ".", VESPA_STRLOC); } return wtype->getNestedType(); } @@ -39,8 +44,7 @@ WeightedSetFieldValue::~WeightedSetFieldValue() { } void WeightedSetFieldValue::verifyKey(const FieldValue & v) { if (!getNestedType().isValueType(v)) { - throw InvalidDataTypeException(*v.getDataType(), getNestedType(), - VESPA_STRLOC); + throw InvalidDataTypeException(*v.getDataType(), getNestedType(), VESPA_STRLOC); } } @@ -92,9 +96,7 @@ WeightedSetFieldValue::increment(const FieldValue& key, int val) } } else { if (it == _map.end()) { - throw vespalib::IllegalStateException("Cannot modify non-existing " - "entry in weightedset without createIfNonExistent set", - VESPA_STRLOC); + throw IllegalStateException("Cannot modify non-existing entry in weightedset without createIfNonExistent set", VESPA_STRLOC); } IntFieldValue& fv = static_cast<IntFieldValue&>(*it->second); fv.setValue(fv.getValue() + val); @@ -203,7 +205,7 @@ WeightedSetFieldValue::find(const FieldValue& key) return _map.find(key); } -FieldValue::IteratorHandler::ModificationStatus +ModificationStatus WeightedSetFieldValue::onIterateNested(PathRange nested, IteratorHandler & handler) const { return _map.iterateNestedImpl(nested, handler, *this); diff --git a/document/src/vespa/document/fieldvalue/weightedsetfieldvalue.h b/document/src/vespa/document/fieldvalue/weightedsetfieldvalue.h index 4d6be1fd35a..5de0bf91614 100644 --- a/document/src/vespa/document/fieldvalue/weightedsetfieldvalue.h +++ b/document/src/vespa/document/fieldvalue/weightedsetfieldvalue.h @@ -7,9 +7,9 @@ */ #pragma once -#include <vespa/document/fieldvalue/collectionfieldvalue.h> -#include <vespa/document/fieldvalue/mapfieldvalue.h> -#include <vespa/document/fieldvalue/intfieldvalue.h> +#include "collectionfieldvalue.h" +#include "mapfieldvalue.h" +#include "intfieldvalue.h" #include <vespa/document/datatype/weightedsetdatatype.h> #include <map> @@ -33,7 +33,7 @@ private: bool addValue(const FieldValue& fval) override { return add(fval, 1); } bool containsValue(const FieldValue& val) const override; bool removeValue(const FieldValue& val) override; - IteratorHandler::ModificationStatus onIterateNested(PathRange nested, IteratorHandler& handler) const override; + fieldvalue::ModificationStatus onIterateNested(PathRange nested, fieldvalue::IteratorHandler& handler) const override; public: typedef std::unique_ptr<WeightedSetFieldValue> UP; diff --git a/document/src/vespa/document/select/parser.h b/document/src/vespa/document/select/parser.h index 61cc6e05876..b25ec951968 100644 --- a/document/src/vespa/document/select/parser.h +++ b/document/src/vespa/document/select/parser.h @@ -2,10 +2,8 @@ #pragma once -#include <memory> -#include <string> -#include <vespa/document/bucket/bucketidfactory.h> #include "node.h" +#include <vespa/document/bucket/bucketidfactory.h> #include <vespa/vespalib/util/exception.h> #include <vespa/vespalib/util/sync.h> diff --git a/document/src/vespa/document/select/result.h b/document/src/vespa/document/select/result.h index 02d8d61700d..ace3f5f717e 100644 --- a/document/src/vespa/document/select/result.h +++ b/document/src/vespa/document/select/result.h @@ -21,8 +21,7 @@ #include <vespa/document/util/printable.h> -namespace document { -namespace select { +namespace document::select { class Result : public Printable { public: @@ -69,6 +68,4 @@ private: Result& operator=(const Result&) = delete; }; -} // select -} // document - +} diff --git a/document/src/vespa/document/select/resultlist.cpp b/document/src/vespa/document/select/resultlist.cpp index f8224b7a158..2cde06fa2f2 100644 --- a/document/src/vespa/document/select/resultlist.cpp +++ b/document/src/vespa/document/select/resultlist.cpp @@ -15,8 +15,7 @@ ResultList::ResultList(const Result& result) { } void -ResultList::add(const FieldValue::IteratorHandler::VariableMap& variables, - const Result& result) +ResultList::add(const fieldvalue::VariableMap& variables, const Result& result) { _results.push_back(ResultPair(variables, &result)); } @@ -27,8 +26,7 @@ ResultList::print(std::ostream& out, bool, const std::string&) const out << "ResultList("; for (uint32_t i = 0; i < _results.size(); i++) { if (!_results[i].first.empty()) { - out << FieldValue::IteratorHandler::toString(_results[i].first) - << " => "; + out << _results[i].first.toString() << " => "; } out << _results[i].second->toString() << " "; } @@ -66,15 +64,12 @@ ResultList::combineResults() const { bool ResultList::combineVariables( - FieldValue::IteratorHandler::VariableMap& output, - const FieldValue::IteratorHandler::VariableMap& input) const + fieldvalue::VariableMap& output, + const fieldvalue::VariableMap& input) const { // First, verify that all variables are overlapping - for (FieldValue::IteratorHandler::VariableMap::const_iterator iter - = output.begin(); iter != output.end(); iter++) - { - FieldValue::IteratorHandler::VariableMap::const_iterator found( - input.find(iter->first)); + for (fieldvalue::VariableMap::const_iterator iter = output.begin(); iter != output.end(); iter++) { + fieldvalue::VariableMap::const_iterator found(input.find(iter->first)); if (found != input.end()) { if (!(found->second == iter->second)) { @@ -83,11 +78,8 @@ ResultList::combineVariables( } } - for (FieldValue::IteratorHandler::VariableMap::const_iterator iter - = input.begin(); iter != input.end(); iter++) - { - FieldValue::IteratorHandler::VariableMap::const_iterator found( - output.find(iter->first)); + for (fieldvalue::VariableMap::const_iterator iter = input.begin(); iter != input.end(); iter++) { + fieldvalue::VariableMap::const_iterator found(output.find(iter->first)); if (found != output.end()) { if (!(found->second == iter->second)) { return false; @@ -95,9 +87,7 @@ ResultList::combineVariables( } } // Ok, variables are overlapping. Add all variables from input to output. - for (FieldValue::IteratorHandler::VariableMap::const_iterator iter - = input.begin(); iter != input.end(); iter++) - { + for (fieldvalue::VariableMap::const_iterator iter = input.begin(); iter != input.end(); iter++) { output[iter->first] = iter->second; } @@ -112,7 +102,7 @@ ResultList::operator&&(const ResultList& other) const // TODO: optimize for (const auto & it : _results) { for (const auto & it2 : other._results) { - FieldValue::IteratorHandler::VariableMap vars = it.first; + fieldvalue::VariableMap vars = it.first; if (combineVariables(vars, it2.first)) { result.add(vars, *it.second && *it2.second); @@ -131,7 +121,7 @@ ResultList::operator||(const ResultList& other) const // TODO: optimize for (const auto & it : _results) { for (const auto & it2 : other._results) { - FieldValue::IteratorHandler::VariableMap vars = it.first; + fieldvalue::VariableMap vars = it.first; if (combineVariables(vars, it2.first)) { result.add(vars, *it.second || *it2.second); diff --git a/document/src/vespa/document/select/resultlist.h b/document/src/vespa/document/select/resultlist.h index 6a3cc1f78d1..a00419d9196 100644 --- a/document/src/vespa/document/select/resultlist.h +++ b/document/src/vespa/document/select/resultlist.h @@ -1,16 +1,15 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once -#include <vector> -#include <vespa/document/fieldvalue/fieldvalue.h> #include "result.h" +#include <vector> +#include <vespa/document/fieldvalue/variablemap.h> -namespace document { -namespace select { +namespace document::select { class ResultList : public Printable { public: - typedef FieldValue::IteratorHandler::VariableMap VariableMap; + using VariableMap = fieldvalue::VariableMap; typedef std::pair<VariableMap, const Result*> ResultPair; typedef std::vector<ResultPair> Results; typedef Results::iterator iterator; @@ -49,7 +48,7 @@ public: private: Results _results; - bool combineVariables(VariableMap& output, const FieldValue::IteratorHandler::VariableMap& input) const; + bool combineVariables(VariableMap& output, const VariableMap& input) const; }; inline bool operator==(const ResultList& list, const Result& other) { @@ -61,5 +60,4 @@ inline bool operator!=(const ResultList& list, const Result& other) { } } -} diff --git a/document/src/vespa/document/select/value.cpp b/document/src/vespa/document/select/value.cpp index 7a453fe5cf3..3540935f8c7 100644 --- a/document/src/vespa/document/select/value.cpp +++ b/document/src/vespa/document/select/value.cpp @@ -2,6 +2,7 @@ #include "value.h" #include "operator.h" +#include <vespa/document/fieldvalue/fieldvalue.h> namespace document { namespace select { diff --git a/document/src/vespa/document/select/value.h b/document/src/vespa/document/select/value.h index 15856648985..b26e959ea1d 100644 --- a/document/src/vespa/document/select/value.h +++ b/document/src/vespa/document/select/value.h @@ -1,4 +1,5 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + /** * @class document::select::Value * @ingroup select @@ -190,7 +191,7 @@ inline ResultList FloatValue::operator==(const FloatValue& value) const class ArrayValue : public Value { public: - typedef std::pair<FieldValue::IteratorHandler::VariableMap, Value::SP> VariableValue; + using VariableValue = std::pair<fieldvalue::VariableMap, Value::SP>; ArrayValue(const std::vector<VariableValue>& values); diff --git a/document/src/vespa/document/select/valuenode.cpp b/document/src/vespa/document/select/valuenode.cpp index 96bc46bd54e..f463c0e3288 100644 --- a/document/src/vespa/document/select/valuenode.cpp +++ b/document/src/vespa/document/select/valuenode.cpp @@ -4,6 +4,7 @@ #include "parser.h" #include <vespa/document/base/exceptions.h> #include <vespa/document/fieldvalue/fieldvalues.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> #include <vespa/document/datatype/documenttype.h> #include <vespa/vespalib/util/md5.h> #include <vespa/document/util/stringutil.h> @@ -16,6 +17,7 @@ LOG_SETUP(".document.select.valuenode"); namespace document { + namespace select { namespace { @@ -157,7 +159,6 @@ VariableValueNode::getValue(const Context& context) const { return context.getValue(_value); } - void VariableValueNode::visit(Visitor &visitor) const { @@ -216,82 +217,48 @@ FieldValueNode::extractFieldName(const std::string & fieldExpression) { throw ParsingFailedException("Fatal: could not extract field name from field expression '" + fieldExpression + "'"); } -void -FieldValueNode::initFieldPath(const DocumentType& type) const { - if (_fieldPath.size() == 0) { - FieldPath::UP path(type.buildFieldPath(_fieldExpression)); - if (!path.get()) { - throw FieldNotFoundException( - vespalib::make_string("Could not create field path for doc type: '%s' field: '%s'", - type.toString().c_str(), _fieldExpression.c_str()), - VESPA_STRLOC); - } - _fieldPath = *path; - } -} - -std::unique_ptr<Value> -FieldValueNode::getValue(const Context& context) const -{ - if (context._doc == NULL) { - return std::unique_ptr<Value>(new InvalidValue()); - } - - const Document& doc = *context._doc; - - if (!documentTypeEqualsName(doc.getType(), _doctype)) { - return std::unique_ptr<Value>(new InvalidValue()); - } - try{ - initFieldPath(doc.getType()); +namespace { - IteratorHandler handler; - doc.iterateNested(_fieldPath.getFullRange(), handler); +class IteratorHandler : public fieldvalue::IteratorHandler { +public: + IteratorHandler(); + ~IteratorHandler(); + bool hasSingleValue() const; + std::unique_ptr<Value> getSingleValue(); + const std::vector<ArrayValue::VariableValue> &getValues(); - if (handler.hasSingleValue()) { - return handler.getSingleValue(); - } else { - const std::vector<ArrayValue::VariableValue>& values = handler.getValues(); +private: + std::unique_ptr<Value> _firstValue; + std::vector<ArrayValue::VariableValue> _values; - if (values.size() == 0) { - return std::unique_ptr<Value>(new NullValue()); - } else { - return std::unique_ptr<Value>(new ArrayValue(handler.getValues())); - } - } - } catch (vespalib::IllegalArgumentException& e) { - LOG(warning, "Caught exception while fetching field from document: %s", e.what()); - return std::unique_ptr<Value>(new InvalidValue()); - } catch (FieldNotFoundException& e) { - LOG(warning, "Tried to compare to field %s, not found in document type", _fieldExpression.c_str()); - return std::unique_ptr<Value>(new InvalidValue()); - } -} + void onPrimitive(uint32_t fid, const Content &fv) override; + std::unique_ptr<Value> getInternalValue(const FieldValue &fval) const; +}; -FieldValueNode::IteratorHandler::IteratorHandler() { } -FieldValueNode::IteratorHandler::~IteratorHandler() { } +IteratorHandler::IteratorHandler() { } +IteratorHandler::~IteratorHandler() { } bool -FieldValueNode::IteratorHandler::hasSingleValue() const { +IteratorHandler::hasSingleValue() const { return _firstValue.get() && (_values.size() == 0); } std::unique_ptr<Value> -FieldValueNode::IteratorHandler::getSingleValue() { +IteratorHandler::getSingleValue() { return std::move(_firstValue); } const std::vector<ArrayValue::VariableValue>& -FieldValueNode::IteratorHandler::getValues() { +IteratorHandler::getValues() { if (_firstValue.get()) { - _values.insert(_values.begin(), ArrayValue::VariableValue(FieldValue::IteratorHandler::VariableMap(), Value::SP(_firstValue.release()))); + _values.insert(_values.begin(), ArrayValue::VariableValue(fieldvalue::VariableMap(), Value::SP(_firstValue.release()))); } return _values; } void -FieldValueNode::IteratorHandler::onPrimitive(uint32_t fid, const Content& fv) { +IteratorHandler::onPrimitive(uint32_t fid, const Content& fv) { (void) fid; if (!_firstValue && getVariables().empty()) { _firstValue = getInternalValue(fv.getValue()); @@ -301,7 +268,7 @@ FieldValueNode::IteratorHandler::onPrimitive(uint32_t fid, const Content& fv) { } std::unique_ptr<Value> -FieldValueNode::IteratorHandler::getInternalValue(const FieldValue& fval) const +IteratorHandler::getInternalValue(const FieldValue& fval) const { switch(fval.getClass().id()) { case document::IntFieldValue::classId: @@ -372,10 +339,63 @@ FieldValueNode::IteratorHandler::getInternalValue(const FieldValue& fval) const } } LOG(warning, "Tried to use unsupported datatype %s in field comparison", - fval.getDataType()->toString().c_str()); + fval.getDataType()->toString().c_str()); return std::make_unique<InvalidValue>(); } +} + +void +FieldValueNode::initFieldPath(const DocumentType& type) const { + if (_fieldPath.size() == 0) { + FieldPath::UP path(type.buildFieldPath(_fieldExpression)); + if (!path.get()) { + throw FieldNotFoundException( + vespalib::make_string("Could not create field path for doc type: '%s' field: '%s'", + type.toString().c_str(), _fieldExpression.c_str()), + VESPA_STRLOC); + } + _fieldPath = *path; + } +} + +std::unique_ptr<Value> +FieldValueNode::getValue(const Context& context) const +{ + if (context._doc == NULL) { + return std::unique_ptr<Value>(new InvalidValue()); + } + + const Document& doc = *context._doc; + + if (!documentTypeEqualsName(doc.getType(), _doctype)) { + return std::unique_ptr<Value>(new InvalidValue()); + } + try{ + initFieldPath(doc.getType()); + + IteratorHandler handler; + doc.iterateNested(_fieldPath.getFullRange(), handler); + + if (handler.hasSingleValue()) { + return handler.getSingleValue(); + } else { + const std::vector<ArrayValue::VariableValue>& values = handler.getValues(); + + if (values.size() == 0) { + return std::unique_ptr<Value>(new NullValue()); + } else { + return std::unique_ptr<Value>(new ArrayValue(handler.getValues())); + } + } + } catch (vespalib::IllegalArgumentException& e) { + LOG(warning, "Caught exception while fetching field from document: %s", e.what()); + return std::unique_ptr<Value>(new InvalidValue()); + } catch (FieldNotFoundException& e) { + LOG(warning, "Tried to compare to field %s, not found in document type", _fieldExpression.c_str()); + return std::unique_ptr<Value>(new InvalidValue()); + } +} void FieldValueNode::visit(Visitor &visitor) const diff --git a/document/src/vespa/document/select/valuenode.h b/document/src/vespa/document/select/valuenode.h index d56b1468508..8aae23cb1e4 100644 --- a/document/src/vespa/document/select/valuenode.h +++ b/document/src/vespa/document/select/valuenode.h @@ -228,23 +228,6 @@ public: static vespalib::string extractFieldName(const std::string & fieldExpression); private: - class IteratorHandler : public FieldValue::IteratorHandler - { - public: - IteratorHandler(); - ~IteratorHandler(); - bool hasSingleValue() const; - - std::unique_ptr<Value> getSingleValue(); - const std::vector<ArrayValue::VariableValue>& getValues(); - - private: - std::unique_ptr<Value> _firstValue; - std::vector<ArrayValue::VariableValue> _values; - - void onPrimitive(uint32_t fid, const Content & fv) override; - std::unique_ptr<Value> getInternalValue(const FieldValue& fval) const; - }; void initFieldPath(const DocumentType&) const; }; diff --git a/document/src/vespa/document/update/addfieldpathupdate.cpp b/document/src/vespa/document/update/addfieldpathupdate.cpp index 03a31d882f3..656ee4580a0 100644 --- a/document/src/vespa/document/update/addfieldpathupdate.cpp +++ b/document/src/vespa/document/update/addfieldpathupdate.cpp @@ -1,8 +1,8 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "addfieldpathupdate.h" -#include <vespa/document/fieldvalue/fieldvalues.h> -#include <vespa/document/select/parser.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> +#include <vespa/document/fieldvalue/arrayfieldvalue.h> #include <vespa/document/serialization/vespadocumentdeserializer.h> #include <vespa/vespalib/objects/nbostream.h> #include <vespa/vespalib/util/exceptions.h> @@ -14,14 +14,13 @@ LOG_SETUP(".document.update.fieldpathupdate"); namespace document { +using namespace fieldvalue; +using vespalib::make_string; + IMPLEMENT_IDENTIFIABLE(AddFieldPathUpdate, FieldPathUpdate); -AddFieldPathUpdate::AddFieldPathUpdate( - const DocumentTypeRepo& repo, - const DataType& type, - stringref fieldPath, - stringref whereClause, - const ArrayFieldValue& values) +AddFieldPathUpdate::AddFieldPathUpdate(const DocumentTypeRepo& repo, const DataType& type, + stringref fieldPath, stringref whereClause, const ArrayFieldValue& values) : FieldPathUpdate(repo, type, fieldPath, whereClause), _values(vespalib::CloneablePtr<ArrayFieldValue>(values.clone())) { @@ -39,22 +38,34 @@ AddFieldPathUpdate::clone() const { return new AddFieldPathUpdate(*this); } -FieldValue::IteratorHandler::ModificationStatus -AddFieldPathUpdate::AddIteratorHandler::doModify(FieldValue& fv) -{ +namespace { + +class AddIteratorHandler : public fieldvalue::IteratorHandler { +public: + AddIteratorHandler(const ArrayFieldValue &values) : _values(values) {} + fieldvalue::ModificationStatus doModify(FieldValue &fv) override; + bool createMissingPath() const override { return true; } + bool onComplex(const fieldvalue::IteratorHandler::Content &) override { return false; } +private: + const ArrayFieldValue &_values; +}; + + +ModificationStatus +AddIteratorHandler::doModify(FieldValue &fv) { LOG(spam, "Adding values to %s", fv.toString().c_str()); if (fv.inherits(CollectionFieldValue::classId)) { - CollectionFieldValue& cf = static_cast<CollectionFieldValue&>(fv); + CollectionFieldValue &cf = static_cast<CollectionFieldValue &>(fv); for (std::size_t i = 0; i < _values.size(); ++i) { cf.add(_values[i]); } } else { - vespalib::string err = vespalib::make_string( - "Unable to add a value to a \"%s\" field value.", - fv.getClass().name()); - throw vespalib::IllegalArgumentException(err, VESPA_STRLOC); + vespalib::string err = make_string("Unable to add a value to a \"%s\" field value.", fv.getClass().name()); + throw vespalib::IllegalArgumentException(err, VESPA_STRLOC); } - return MODIFIED; + return ModificationStatus::MODIFIED; +} + } bool @@ -68,8 +79,7 @@ AddFieldPathUpdate::operator==(const FieldPathUpdate& other) const } void -AddFieldPathUpdate::print(std::ostream& out, bool verbose, - const std::string& indent) const +AddFieldPathUpdate::print(std::ostream& out, bool verbose, const std::string& indent) const { out << "AddFieldPathUpdate(\n"; FieldPathUpdate::print(out, verbose, indent + " "); @@ -79,8 +89,7 @@ AddFieldPathUpdate::print(std::ostream& out, bool verbose, } void -AddFieldPathUpdate::deserialize(const DocumentTypeRepo& repo, - const DataType& type, +AddFieldPathUpdate::deserialize(const DocumentTypeRepo& repo, const DataType& type, ByteBuffer& buffer, uint16_t version) { FieldPathUpdate::deserialize(repo, type, buffer, version); @@ -95,4 +104,11 @@ AddFieldPathUpdate::deserialize(const DocumentTypeRepo& repo, buffer.incPos(buffer.getRemaining() - stream.size()); } +std::unique_ptr<IteratorHandler> +AddFieldPathUpdate::getIteratorHandler(Document&) const { + return std::make_unique<AddIteratorHandler>(*_values); +} + + + } // ns document diff --git a/document/src/vespa/document/update/addfieldpathupdate.h b/document/src/vespa/document/update/addfieldpathupdate.h index 6d75ebc4209..94156156257 100644 --- a/document/src/vespa/document/update/addfieldpathupdate.h +++ b/document/src/vespa/document/update/addfieldpathupdate.h @@ -10,7 +10,6 @@ class AddFieldPathUpdate : public FieldPathUpdate public: /** For deserialization */ AddFieldPathUpdate(); - AddFieldPathUpdate(const DocumentTypeRepo& repo, const DataType& type, stringref fieldPath, stringref whereClause, const ArrayFieldValue& values); ~AddFieldPathUpdate(); @@ -18,7 +17,6 @@ public: FieldPathUpdate* clone() const override; bool operator==(const FieldPathUpdate& other) const override; void print(std::ostream& out, bool verbose, const std::string& indent) const override; - const ArrayFieldValue & getValues() const { return *_values; } DECLARE_IDENTIFIABLE(AddFieldPathUpdate); @@ -29,22 +27,7 @@ private: void deserialize(const DocumentTypeRepo& repo, const DataType& type, ByteBuffer& buffer, uint16_t version) override; - class AddIteratorHandler : public FieldValue::IteratorHandler - { - public: - AddIteratorHandler(const ArrayFieldValue& values) : _values(values) { } - - ModificationStatus doModify(FieldValue& fv) override; - bool createMissingPath() const override { return true; } - bool onComplex(const Content&) override { return false; } - private: - const ArrayFieldValue& _values; - }; - - std::unique_ptr<FieldValue::IteratorHandler> getIteratorHandler(Document&) const override { - return std::unique_ptr<FieldValue::IteratorHandler>( - new AddIteratorHandler(*_values)); - } + std::unique_ptr<fieldvalue::IteratorHandler> getIteratorHandler(Document&) const override; vespalib::CloneablePtr<ArrayFieldValue> _values; }; diff --git a/document/src/vespa/document/update/addvalueupdate.cpp b/document/src/vespa/document/update/addvalueupdate.cpp index 910e3d7dd50..b1142836fc2 100644 --- a/document/src/vespa/document/update/addvalueupdate.cpp +++ b/document/src/vespa/document/update/addvalueupdate.cpp @@ -2,17 +2,17 @@ #include "addvalueupdate.h" #include <vespa/document/base/field.h> #include <vespa/document/datatype/arraydatatype.h> -#include <vespa/document/datatype/weightedsetdatatype.h> #include <vespa/document/fieldvalue/fieldvalues.h> -#include <vespa/document/repo/fixedtyperepo.h> #include <vespa/document/serialization/vespadocumentdeserializer.h> -#include <vespa/document/util/serializable.h> #include <vespa/document/util/serializableexceptions.h> #include <vespa/vespalib/objects/nbostream.h> +#include <vespa/vespalib/util/xmlstream.h> + using vespalib::IllegalArgumentException; using vespalib::IllegalStateException; using vespalib::nbostream; +using namespace vespalib::xml; namespace document { diff --git a/document/src/vespa/document/update/arithmeticvalueupdate.cpp b/document/src/vespa/document/update/arithmeticvalueupdate.cpp index 29c24e7140f..a8fe541d0fe 100644 --- a/document/src/vespa/document/update/arithmeticvalueupdate.cpp +++ b/document/src/vespa/document/update/arithmeticvalueupdate.cpp @@ -3,9 +3,11 @@ #include <vespa/document/base/field.h> #include <vespa/document/fieldvalue/fieldvalues.h> #include <vespa/vespalib/util/exceptions.h> +#include <vespa/vespalib/util/xmlstream.h> using vespalib::IllegalArgumentException; using vespalib::IllegalStateException; +using namespace vespalib::xml; namespace document { diff --git a/document/src/vespa/document/update/assignfieldpathupdate.cpp b/document/src/vespa/document/update/assignfieldpathupdate.cpp index 4b8ee510576..3d67a589ea5 100644 --- a/document/src/vespa/document/update/assignfieldpathupdate.cpp +++ b/document/src/vespa/document/update/assignfieldpathupdate.cpp @@ -2,6 +2,7 @@ #include "assignfieldpathupdate.h" #include <vespa/document/fieldvalue/fieldvalues.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> #include <vespa/document/select/parser.h> #include <vespa/document/select/variablemap.h> #include <vespa/document/serialization/vespadocumentdeserializer.h> @@ -16,6 +17,8 @@ using vespalib::nbostream; namespace document { +using namespace fieldvalue; + IMPLEMENT_IDENTIFIABLE(AssignFieldPathUpdate, FieldPathUpdate); AssignFieldPathUpdate::AssignFieldPathUpdate() @@ -69,24 +72,56 @@ FieldPathUpdate* AssignFieldPathUpdate::clone() const { return new AssignFieldPathUpdate(*this); } +namespace { -std::unique_ptr<FieldValue::IteratorHandler> -AssignFieldPathUpdate::getIteratorHandler(Document& doc) const +class AssignValueIteratorHandler : public IteratorHandler { - if (!_expression.empty()) { - return std::unique_ptr<FieldValue::IteratorHandler>( - new AssignExpressionIteratorHandler( - *_repo, doc, _expression, _removeIfZero, _createMissingPath)); - } else { - return std::unique_ptr<FieldValue::IteratorHandler>( - new AssignValueIteratorHandler( - *_newValue, _removeIfZero, _createMissingPath)); - } -} - - -FieldValue::IteratorHandler::ModificationStatus -AssignFieldPathUpdate::AssignValueIteratorHandler::doModify(FieldValue& fv) { +public: + AssignValueIteratorHandler(const FieldValue& newValue, + bool removeIfZero, + bool createMissingPath_) + : _newValue(newValue), _removeIfZero(removeIfZero), + _createMissingPath(createMissingPath_) + {} + + ModificationStatus doModify(FieldValue& fv) override; + bool onComplex(const Content&) override { return false; } + bool createMissingPath() const override { return _createMissingPath; } + +private: + const FieldValue& _newValue; + bool _removeIfZero; + bool _createMissingPath; +}; + +class AssignExpressionIteratorHandler : public IteratorHandler +{ +public: + AssignExpressionIteratorHandler( + const DocumentTypeRepo& repo, + Document& doc, + const vespalib::string& expression, + bool removeIfZero, + bool createMissingPath_) + : _calc(repo, expression), + _doc(doc), + _removeIfZero(removeIfZero), + _createMissingPath(createMissingPath_) + {} + + ModificationStatus doModify(FieldValue& fv) override; + bool onComplex(const Content&) override { return false; } + bool createMissingPath() const override { return _createMissingPath; } + +private: + DocumentCalculator _calc; + Document& _doc; + bool _removeIfZero; + bool _createMissingPath; +}; + +ModificationStatus +AssignValueIteratorHandler::doModify(FieldValue& fv) { LOG(spam, "fv = %s", fv.toString().c_str()); if (!(*fv.getDataType() == *_newValue.getDataType())) { std::string err = vespalib::make_string( @@ -105,8 +140,8 @@ AssignFieldPathUpdate::AssignValueIteratorHandler::doModify(FieldValue& fv) { return MODIFIED; } -FieldValue::IteratorHandler::ModificationStatus -AssignFieldPathUpdate::AssignExpressionIteratorHandler::doModify(FieldValue& fv) { +ModificationStatus +AssignExpressionIteratorHandler::doModify(FieldValue& fv) { LOG(spam, "fv = %s", fv.toString().c_str()); if (fv.inherits(NumericFieldValueBase::classId)) { std::unique_ptr<select::VariableMap> varHolder = std::make_unique<select::VariableMap>(); @@ -146,6 +181,18 @@ AssignFieldPathUpdate::AssignExpressionIteratorHandler::doModify(FieldValue& fv) return MODIFIED; } +} + +std::unique_ptr<IteratorHandler> +AssignFieldPathUpdate::getIteratorHandler(Document& doc) const +{ + if (!_expression.empty()) { + return std::make_unique<AssignExpressionIteratorHandler>(*_repo, doc, _expression, _removeIfZero, _createMissingPath); + } else { + return std::make_unique<AssignValueIteratorHandler>(*_newValue, _removeIfZero, _createMissingPath); + } +} + bool AssignFieldPathUpdate::operator==(const FieldPathUpdate& other) const { diff --git a/document/src/vespa/document/update/assignfieldpathupdate.h b/document/src/vespa/document/update/assignfieldpathupdate.h index 81853246e54..3794cb331ce 100644 --- a/document/src/vespa/document/update/assignfieldpathupdate.h +++ b/document/src/vespa/document/update/assignfieldpathupdate.h @@ -58,53 +58,7 @@ private: void deserialize(const DocumentTypeRepo& repo, const DataType& type, ByteBuffer& buffer, uint16_t version) override; - class AssignValueIteratorHandler : public FieldValue::IteratorHandler - { - public: - AssignValueIteratorHandler(const FieldValue& newValue, - bool removeIfZero, - bool createMissingPath_) - : _newValue(newValue), _removeIfZero(removeIfZero), - _createMissingPath(createMissingPath_) - {} - - ModificationStatus doModify(FieldValue& fv) override; - bool onComplex(const Content&) override { return false; } - bool createMissingPath() const override { return _createMissingPath; } - - private: - const FieldValue& _newValue; - bool _removeIfZero; - bool _createMissingPath; - }; - - class AssignExpressionIteratorHandler : public FieldValue::IteratorHandler - { - public: - AssignExpressionIteratorHandler( - const DocumentTypeRepo& repo, - Document& doc, - const vespalib::string& expression, - bool removeIfZero, - bool createMissingPath_) - : _calc(repo, expression), - _doc(doc), - _removeIfZero(removeIfZero), - _createMissingPath(createMissingPath_) - {} - - ModificationStatus doModify(FieldValue& fv) override; - bool onComplex(const Content&) override { return false; } - bool createMissingPath() const override { return _createMissingPath; } - - private: - DocumentCalculator _calc; - Document& _doc; - bool _removeIfZero; - bool _createMissingPath; - }; - - std::unique_ptr<FieldValue::IteratorHandler> getIteratorHandler(Document& doc) const override; + std::unique_ptr<fieldvalue::IteratorHandler> getIteratorHandler(Document& doc) const override; const DocumentTypeRepo *_repo; FieldValue::CP _newValue; diff --git a/document/src/vespa/document/update/assignvalueupdate.cpp b/document/src/vespa/document/update/assignvalueupdate.cpp index 0538bec10e5..63609ed18c1 100644 --- a/document/src/vespa/document/update/assignvalueupdate.cpp +++ b/document/src/vespa/document/update/assignvalueupdate.cpp @@ -3,14 +3,16 @@ #include "assignvalueupdate.h" #include <vespa/document/base/field.h> #include <vespa/document/fieldvalue/fieldvalues.h> -#include <vespa/document/repo/fixedtyperepo.h> #include <vespa/document/serialization/vespadocumentdeserializer.h> #include <vespa/vespalib/objects/nbostream.h> #include <vespa/vespalib/util/exceptions.h> +#include <vespa/vespalib/util/xmlstream.h> + using vespalib::IllegalArgumentException; using vespalib::IllegalStateException; using vespalib::nbostream; +using namespace vespalib::xml; namespace document { diff --git a/document/src/vespa/document/update/clearvalueupdate.cpp b/document/src/vespa/document/update/clearvalueupdate.cpp index cb526852299..f34987ccfeb 100644 --- a/document/src/vespa/document/update/clearvalueupdate.cpp +++ b/document/src/vespa/document/update/clearvalueupdate.cpp @@ -4,10 +4,12 @@ #include <vespa/document/base/field.h> #include <vespa/document/fieldvalue/document.h> #include <vespa/vespalib/util/exceptions.h> +#include <vespa/vespalib/util/xmlstream.h> #include <ostream> using vespalib::IllegalArgumentException; using vespalib::IllegalStateException; +using namespace vespalib::xml; namespace document { diff --git a/document/src/vespa/document/update/documentupdate.cpp b/document/src/vespa/document/update/documentupdate.cpp index d91b33650d4..43fe6c28dc8 100644 --- a/document/src/vespa/document/update/documentupdate.cpp +++ b/document/src/vespa/document/update/documentupdate.cpp @@ -9,12 +9,14 @@ #include <vespa/document/util/bufferexceptions.h> #include <vespa/document/base/exceptions.h> #include <vespa/document/datatype/documenttype.h> +#include <vespa/vespalib/util/xmlstream.h> using vespalib::IllegalArgumentException; using vespalib::IllegalStateException; using vespalib::nbostream; using vespalib::make_string; using vespalib::string; +using namespace vespalib::xml; namespace document { diff --git a/document/src/vespa/document/update/fieldpathupdate.cpp b/document/src/vespa/document/update/fieldpathupdate.cpp index a4145a9b58a..37672ac0b1d 100644 --- a/document/src/vespa/document/update/fieldpathupdate.cpp +++ b/document/src/vespa/document/update/fieldpathupdate.cpp @@ -1,14 +1,20 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/document/fieldvalue/fieldvalues.h> +#include "fieldpathupdates.h" +#include <vespa/document/fieldvalue/document.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> #include <vespa/document/select/parser.h> -#include <vespa/document/update/fieldpathupdates.h> #include <vespa/document/util/serializableexceptions.h> #include <vespa/log/log.h> LOG_SETUP(".document.update.fieldpathupdate"); +using vespalib::make_string; +using vespalib::IllegalArgumentException; + namespace document { +using namespace fieldvalue; + IMPLEMENT_IDENTIFIABLE_ABSTRACT(FieldPathUpdate, Identifiable); namespace { @@ -43,9 +49,9 @@ FieldPathUpdate::FieldPathUpdate(const DocumentTypeRepo& repo, : std::unique_ptr<select::Node>()) { if (!_fieldPath.get()) { - throw vespalib::IllegalArgumentException( - vespalib::make_string("Could not create field path update for: path='%s', where='%s'", - fieldPath.c_str(), whereClause.c_str()), VESPA_STRLOC); + throw IllegalArgumentException( + make_string("Could not create field path update for: path='%s', where='%s'", + fieldPath.c_str(), whereClause.c_str()), VESPA_STRLOC); } } @@ -61,7 +67,7 @@ FieldPathUpdate::operator==(const FieldPathUpdate& other) const void FieldPathUpdate::applyTo(Document& doc) const { - std::unique_ptr<FieldValue::IteratorHandler> handler(getIteratorHandler(doc)); + std::unique_ptr<IteratorHandler> handler(getIteratorHandler(doc)); if (!_whereClause) { doc.iterateNested(*_fieldPath, *handler); @@ -70,7 +76,7 @@ FieldPathUpdate::applyTo(Document& doc) const for (select::ResultList::const_iterator i = results.begin(); i != results.end(); ++i) { - LOG(spam, "vars = %s", FieldValue::IteratorHandler::toString(handler->getVariables()).c_str()); + LOG(spam, "vars = %s", handler->getVariables().toString().c_str()); if (*i->second == select::Result::True) { handler->setVariables(i->first); doc.iterateNested(*_fieldPath, *handler); @@ -88,8 +94,7 @@ FieldPathUpdate::affectsDocumentBody() const } void -FieldPathUpdate::print(std::ostream& out, bool, - const std::string& indent) const +FieldPathUpdate::print(std::ostream& out, bool, const std::string& indent) const { out << indent << "fieldPath='" << _originalFieldPath << "',\n" << indent << "whereClause='" << _originalWhereClause << "'"; @@ -99,10 +104,10 @@ void FieldPathUpdate::checkCompatibility(const FieldValue& fv) const { if ( !getResultingDataType().isValueType(fv)) { - throw vespalib::IllegalArgumentException( - vespalib::make_string("Cannot update a '%s' field with a '%s' value", - getResultingDataType().toString().c_str(), - fv.getDataType()->toString().c_str()), + throw IllegalArgumentException( + make_string("Cannot update a '%s' field with a '%s' value", + getResultingDataType().toString().c_str(), + fv.getDataType()->toString().c_str()), VESPA_STRLOC); } } @@ -111,8 +116,7 @@ const DataType& FieldPathUpdate::getResultingDataType() const { if (_fieldPath->empty()) { - throw vespalib::IllegalStateException("Cannot get resulting data " - "type from an empty field path", VESPA_STRLOC); + throw vespalib::IllegalStateException("Cannot get resulting data type from an empty field path", VESPA_STRLOC); } return _fieldPath->rbegin()->getDataType(); } @@ -138,9 +142,7 @@ FieldPathUpdate::deserialize(const DocumentTypeRepo& repo, try { _fieldPath = type.buildFieldPath(_originalFieldPath).release(); if (!_fieldPath.get()) { - throw DeserializeException( - vespalib::make_string("Invalid field path: '%s'", _originalFieldPath.c_str()), - VESPA_STRLOC); + throw DeserializeException(make_string("Invalid field path: '%s'", _originalFieldPath.c_str()), VESPA_STRLOC); } _whereClause = !_originalWhereClause.empty() ? parseDocumentSelection(_originalWhereClause, repo) @@ -159,8 +161,7 @@ FieldPathUpdate::createInstance(const DocumentTypeRepo& repo, buffer.getByte(updateType); std::unique_ptr<FieldPathUpdate> update; - switch (updateType) - { + switch (updateType) { case 0: update.reset(new AssignFieldPathUpdate()); break; @@ -171,9 +172,7 @@ FieldPathUpdate::createInstance(const DocumentTypeRepo& repo, update.reset(new AddFieldPathUpdate()); break; default: - throw DeserializeException( - vespalib::make_string("Unknown fieldpath update type: %d", updateType), - VESPA_STRLOC); + throw DeserializeException(make_string("Unknown fieldpath update type: %d", updateType), VESPA_STRLOC); } update->deserialize(repo, type, buffer, serializationVersion); return update; diff --git a/document/src/vespa/document/update/fieldpathupdate.h b/document/src/vespa/document/update/fieldpathupdate.h index 80a63d62281..0eaff9485bf 100644 --- a/document/src/vespa/document/update/fieldpathupdate.h +++ b/document/src/vespa/document/update/fieldpathupdate.h @@ -104,8 +104,7 @@ protected: enum SerializedMagic {AssignMagic=0, RemoveMagic=1, AddMagic=2}; private: // TODO: rename to createIteratorHandler? - virtual std::unique_ptr<FieldValue::IteratorHandler> getIteratorHandler( - Document& doc) const = 0; + virtual std::unique_ptr<fieldvalue::IteratorHandler> getIteratorHandler(Document& doc) const = 0; vespalib::string _originalFieldPath; vespalib::string _originalWhereClause; diff --git a/document/src/vespa/document/update/mapvalueupdate.cpp b/document/src/vespa/document/update/mapvalueupdate.cpp index 0a92fa7fb15..37d775bb204 100644 --- a/document/src/vespa/document/update/mapvalueupdate.cpp +++ b/document/src/vespa/document/update/mapvalueupdate.cpp @@ -5,13 +5,14 @@ #include <vespa/document/serialization/vespadocumentdeserializer.h> #include <vespa/vespalib/objects/nbostream.h> #include <vespa/document/util/serializableexceptions.h> +#include <vespa/vespalib/util/xmlstream.h> using vespalib::IllegalArgumentException; using vespalib::IllegalStateException; using vespalib::nbostream; +using namespace vespalib::xml; -namespace document -{ +namespace document { IMPLEMENT_IDENTIFIABLE(MapValueUpdate, ValueUpdate); diff --git a/document/src/vespa/document/update/removefieldpathupdate.cpp b/document/src/vespa/document/update/removefieldpathupdate.cpp index 6c9d60abd2f..4af867995d9 100644 --- a/document/src/vespa/document/update/removefieldpathupdate.cpp +++ b/document/src/vespa/document/update/removefieldpathupdate.cpp @@ -1,11 +1,13 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "removefieldpathupdate.h" -#include <vespa/document/fieldvalue/fieldvalues.h> -#include <vespa/document/select/parser.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> +#include <ostream> namespace document { +using namespace fieldvalue; + IMPLEMENT_IDENTIFIABLE(RemoveFieldPathUpdate, FieldPathUpdate); RemoveFieldPathUpdate::RemoveFieldPathUpdate() @@ -30,8 +32,7 @@ RemoveFieldPathUpdate::operator==(const FieldPathUpdate& other) const } void -RemoveFieldPathUpdate::print(std::ostream& out, bool verbose, - const std::string& indent) const +RemoveFieldPathUpdate::print(std::ostream& out, bool verbose, const std::string& indent) const { out << "RemoveFieldPathUpdate(\n"; FieldPathUpdate::print(out, verbose, indent + " "); @@ -39,11 +40,28 @@ RemoveFieldPathUpdate::print(std::ostream& out, bool verbose, } void -RemoveFieldPathUpdate::deserialize( - const DocumentTypeRepo& repo, const DataType& type, - ByteBuffer& buffer, uint16_t version) +RemoveFieldPathUpdate::deserialize(const DocumentTypeRepo& repo, const DataType& type, + ByteBuffer& buffer, uint16_t version) { FieldPathUpdate::deserialize(repo, type, buffer, version); } +namespace { + +class RemoveIteratorHandler : public IteratorHandler { +public: + RemoveIteratorHandler() {} + + ModificationStatus doModify(FieldValue &) override { + return ModificationStatus::REMOVED; + } +}; + +} + +std::unique_ptr<IteratorHandler> +RemoveFieldPathUpdate::getIteratorHandler(Document&) const { + return std::make_unique<RemoveIteratorHandler>(); +} + } // ns document diff --git a/document/src/vespa/document/update/removefieldpathupdate.h b/document/src/vespa/document/update/removefieldpathupdate.h index 6de2a105cbf..1a3865fe761 100644 --- a/document/src/vespa/document/update/removefieldpathupdate.h +++ b/document/src/vespa/document/update/removefieldpathupdate.h @@ -29,19 +29,7 @@ private: void deserialize(const DocumentTypeRepo& repo, const DataType& type, ByteBuffer& buffer, uint16_t version) override; - class RemoveIteratorHandler : public FieldValue::IteratorHandler - { - public: - RemoveIteratorHandler() {} - - ModificationStatus doModify(FieldValue&) override { - return REMOVED; - } - }; - - std::unique_ptr<FieldValue::IteratorHandler> getIteratorHandler(Document&) const override { - return std::make_unique<RemoveIteratorHandler>(); - } + std::unique_ptr<fieldvalue::IteratorHandler> getIteratorHandler(Document&) const override; }; diff --git a/document/src/vespa/document/update/removevalueupdate.cpp b/document/src/vespa/document/update/removevalueupdate.cpp index e0575f600da..34af57edbe8 100644 --- a/document/src/vespa/document/update/removevalueupdate.cpp +++ b/document/src/vespa/document/update/removevalueupdate.cpp @@ -1,20 +1,20 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "removevalueupdate.h" #include <vespa/document/base/field.h> #include <vespa/document/datatype/arraydatatype.h> #include <vespa/document/datatype/weightedsetdatatype.h> #include <vespa/document/fieldvalue/fieldvalues.h> -#include <vespa/document/repo/fixedtyperepo.h> #include <vespa/document/serialization/vespadocumentdeserializer.h> -#include <vespa/document/update/removevalueupdate.h> #include <vespa/vespalib/objects/nbostream.h> #include <vespa/document/util/serializableexceptions.h> +#include <vespa/vespalib/util/xmlstream.h> using vespalib::IllegalArgumentException; using vespalib::IllegalStateException; using vespalib::nbostream; +using namespace vespalib::xml; -namespace document -{ +namespace document { IMPLEMENT_IDENTIFIABLE(RemoveValueUpdate, ValueUpdate); diff --git a/document/src/vespa/document/util/xmlserializable.h b/document/src/vespa/document/util/xmlserializable.h index 21e0b858dec..f74761a04f6 100644 --- a/document/src/vespa/document/util/xmlserializable.h +++ b/document/src/vespa/document/util/xmlserializable.h @@ -5,14 +5,6 @@ #include <vespa/vespalib/util/xmlserializable.h> namespace document { - typedef vespalib::xml::XmlOutputStream XmlOutputStream; - typedef vespalib::xml::XmlSerializable XmlSerializable; - typedef vespalib::xml::XmlTag XmlTag; - typedef vespalib::xml::XmlEndTag XmlEndTag; - typedef vespalib::xml::XmlAttribute XmlAttribute; - typedef vespalib::xml::XmlContent XmlContent; - typedef vespalib::xml::XmlEscapedContent XmlEscapedContent; - typedef vespalib::xml::XmlBase64Content XmlBase64Content; - typedef vespalib::xml::XmlContentWrapper XmlContentWrapper; + using XmlSerializable = vespalib::xml::XmlSerializable; + using XmlOutputStream = vespalib::xml::XmlOutputStream; } - diff --git a/memfilepersistence/src/vespa/memfilepersistence/device/devicemanager.cpp b/memfilepersistence/src/vespa/memfilepersistence/device/devicemanager.cpp index 2ae27f06671..ba249df2b73 100644 --- a/memfilepersistence/src/vespa/memfilepersistence/device/devicemanager.cpp +++ b/memfilepersistence/src/vespa/memfilepersistence/device/devicemanager.cpp @@ -2,6 +2,7 @@ #include "devicemanager.h" #include <vespa/vespalib/util/exceptions.h> +#include <vespa/vespalib/util/xmlstream.h> namespace storage::memfile { diff --git a/memfilepersistence/src/vespa/memfilepersistence/device/partitionmonitor.cpp b/memfilepersistence/src/vespa/memfilepersistence/device/partitionmonitor.cpp index b5b94d29336..b0cbe4fdbf7 100644 --- a/memfilepersistence/src/vespa/memfilepersistence/device/partitionmonitor.cpp +++ b/memfilepersistence/src/vespa/memfilepersistence/device/partitionmonitor.cpp @@ -3,13 +3,12 @@ #include "partitionmonitor.h" #include <vespa/vespalib/util/exceptions.h> #include <vespa/vespalib/stllike/asciistream.h> +#include <vespa/vespalib/util/xmlstream.h> #include <vespa/log/log.h> LOG_SETUP(".persistence.device.partition.monitor"); -namespace storage { - -namespace memfile { +namespace storage::memfile { namespace { @@ -387,5 +386,3 @@ PartitionMonitor::overrideRealStat(uint32_t blockSize, uint32_t totalBlocks, } } - -} // storage diff --git a/memfilepersistence/src/vespa/memfilepersistence/memfile/shared_data_location_tracker.h b/memfilepersistence/src/vespa/memfilepersistence/memfile/shared_data_location_tracker.h index e0b1a7b9a2a..42d3fb0b238 100644 --- a/memfilepersistence/src/vespa/memfilepersistence/memfile/shared_data_location_tracker.h +++ b/memfilepersistence/src/vespa/memfilepersistence/memfile/shared_data_location_tracker.h @@ -2,6 +2,7 @@ #pragma once #include <vespa/memfilepersistence/common/types.h> +#include <map> namespace storage { namespace memfile { diff --git a/metrics/src/tests/metricmanagertest.cpp b/metrics/src/tests/metricmanagertest.cpp index 0ba6bdfbd2f..e4a2761cd73 100644 --- a/metrics/src/tests/metricmanagertest.cpp +++ b/metrics/src/tests/metricmanagertest.cpp @@ -9,6 +9,7 @@ #include <vespa/vdstestlib/cppunit/macros.h> #include <vespa/vespalib/stllike/asciistream.h> #include <vespa/vespalib/data/slime/slime.h> +#include <vespa/vespalib/util/xmlstream.h> #include <vespa/log/log.h> LOG_SETUP(".test.metricmanager"); diff --git a/metrics/src/vespa/metrics/xmlwriter.cpp b/metrics/src/vespa/metrics/xmlwriter.cpp index 66f83cdd4bf..4a998b79294 100644 --- a/metrics/src/vespa/metrics/xmlwriter.cpp +++ b/metrics/src/vespa/metrics/xmlwriter.cpp @@ -1,11 +1,11 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/metrics/xmlwriter.h> - -#include <vespa/metrics/countmetric.h> -#include <vespa/metrics/metricset.h> -#include <vespa/metrics/metricsnapshot.h> -#include <vespa/metrics/valuemetric.h> +#include "xmlwriter.h" +#include "countmetric.h" +#include "metricset.h" +#include "metricsnapshot.h" +#include "valuemetric.h" +#include <vespa/vespalib/util/xmlstream.h> #include <sstream> namespace metrics { diff --git a/searchcore/src/apps/vespa-transactionlog-inspect/vespa-transactionlog-inspect.cpp b/searchcore/src/apps/vespa-transactionlog-inspect/vespa-transactionlog-inspect.cpp index 95c6d39c51a..0fdfb09ecef 100644 --- a/searchcore/src/apps/vespa-transactionlog-inspect/vespa-transactionlog-inspect.cpp +++ b/searchcore/src/apps/vespa-transactionlog-inspect/vespa-transactionlog-inspect.cpp @@ -8,6 +8,7 @@ #include <vespa/searchlib/transactionlog/translogclient.h> #include <vespa/searchlib/transactionlog/translogserver.h> #include <vespa/vespalib/util/programoptions.h> +#include <vespa/vespalib/util/xmlstream.h> #include <vespa/document/config/config-documenttypes.h> #include <iostream> #include <vespa/config/helper/configgetter.hpp> diff --git a/searchcore/src/vespa/searchcore/proton/test/userdocuments.h b/searchcore/src/vespa/searchcore/proton/test/userdocuments.h index d1ea6f6ab4c..6b5a911352b 100644 --- a/searchcore/src/vespa/searchcore/proton/test/userdocuments.h +++ b/searchcore/src/vespa/searchcore/proton/test/userdocuments.h @@ -2,10 +2,9 @@ #pragma once #include "bucketdocuments.h" +#include <map> -namespace proton { - -namespace test { +namespace proton::test { /** * Collection of documents for a set of users, @@ -48,7 +47,4 @@ public: void clear() { _docs.clear(); } }; -} // namespace test - -} // namespace proton - +} diff --git a/searchlib/src/tests/aggregator/perdocexpr.cpp b/searchlib/src/tests/aggregator/perdocexpr.cpp index 6f374f1bea4..512252fd732 100644 --- a/searchlib/src/tests/aggregator/perdocexpr.cpp +++ b/searchlib/src/tests/aggregator/perdocexpr.cpp @@ -5,14 +5,13 @@ #include <vespa/searchlib/attribute/extendableattributes.h> #include <vespa/vespalib/objects/objectdumper.h> #include <vespa/vespalib/testkit/testapp.h> -#include <stdexcept> #include <vespa/document/base/testdocman.h> #include <vespa/vespalib/util/md5.h> -#include <vespa/vespalib/util/stringfmt.h> #include <vespa/searchlib/expression/getdocidnamespacespecificfunctionnode.h> #include <vespa/searchlib/expression/documentfieldnode.h> #include <cmath> #include <iostream> +#include <list> #define MU std::make_unique diff --git a/searchlib/src/vespa/searchlib/expression/documentfieldnode.h b/searchlib/src/vespa/searchlib/expression/documentfieldnode.h index a6c027beb22..2a202fe562e 100644 --- a/searchlib/src/vespa/searchlib/expression/documentfieldnode.h +++ b/searchlib/src/vespa/searchlib/expression/documentfieldnode.h @@ -4,6 +4,7 @@ #include "documentaccessornode.h" #include "resultnode.h" #include "resultvector.h" +#include <vespa/document/fieldvalue/iteratorhandler.h> namespace search { namespace expression { @@ -38,11 +39,9 @@ public: DocumentFieldNode & operator = (const DocumentFieldNode & rhs); const vespalib::string & getFieldName() const override { return _fieldName; } private: - class Handler : public document::FieldValue::IteratorHandler { + class Handler : public document::fieldvalue::IteratorHandler { public: virtual void reset() = 0; - protected: - typedef document::FieldValue::IteratorHandler::Content Content; private: void onCollectionStart(const Content & c) override; void onStructStart(const Content & c) override; diff --git a/staging_vespalib/src/tests/xmlserializable/xmlserializabletest.cpp b/staging_vespalib/src/tests/xmlserializable/xmlserializabletest.cpp index 90fcdb8f94f..4af70f7e6fe 100644 --- a/staging_vespalib/src/tests/xmlserializable/xmlserializabletest.cpp +++ b/staging_vespalib/src/tests/xmlserializable/xmlserializabletest.cpp @@ -1,7 +1,7 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/testkit/testapp.h> -#include <vespa/vespalib/util/xmlserializable.h> +#include <vespa/vespalib/util/xmlstream.h> namespace vespalib { diff --git a/staging_vespalib/src/vespa/vespalib/util/CMakeLists.txt b/staging_vespalib/src/vespa/vespalib/util/CMakeLists.txt index ca440428e0a..3b36b863707 100644 --- a/staging_vespalib/src/vespa/vespalib/util/CMakeLists.txt +++ b/staging_vespalib/src/vespa/vespalib/util/CMakeLists.txt @@ -18,5 +18,6 @@ vespa_add_library(staging_vespalib_vespalib_util OBJECT shutdownguard.cpp timer.cpp xmlserializable.cpp + xmlstream.cpp DEPENDS ) diff --git a/staging_vespalib/src/vespa/vespalib/util/polymorphicarray.h b/staging_vespalib/src/vespa/vespalib/util/polymorphicarray.h new file mode 100644 index 00000000000..6c4d8e37311 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/util/polymorphicarray.h @@ -0,0 +1,82 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// +#pragma once + +#include "polymorphicarraybase.h" + +namespace vespalib { + +/** + * Describes an interface an array of polymorphic types. + * The intention is to allow efficient implementations when that is possible + * while still enjoying the flexibility of the polymorph interface. + * It is not a full feldged Array implementation as std::vector. It contains just + * the minimum required to allow for efficient implementations for document::ArrayFieldValue. + * + * You specify the base type the interface shall provide. This base type must define + * virtual void assign(const B & rhs); + * For use with ComplexArrayT your type also need + * virtual T * clone() const; + */ +template<typename B> +class IArrayT : public IArrayBase { +public: + class iterator { + public: + iterator(IArrayT &a, size_t i) : _a(&a), _i(i) {} + iterator operator+(size_t diff) const { return iterator(*_a, _i + diff); } + iterator &operator++() { + ++_i; + return *this; + } + iterator operator++(int) { + iterator other(*this); + ++_i; + return other; + } + bool operator==(const iterator &other) const { return (_a == other._a) && (_i == other._i); } + bool operator!=(const iterator &other) const { return (_i != other._i) || (_a != other._a); } + B &operator*() { return (*_a)[_i]; } + B *operator->() { return &(*_a)[_i]; } + friend ssize_t operator-(const iterator &a, const iterator &b) { return a._i - b._i; } + private: + IArrayT *_a; + size_t _i; + }; + + class const_iterator { + public: + const_iterator(const IArrayT &a, size_t i) : _a(&a), _i(i) {} + const_iterator operator+(size_t diff) const { return const_iterator(*_a, _i + diff); } + const_iterator &operator++() { + ++_i; + return *this; + } + const_iterator operator++(int) { + const_iterator other(*this); + ++_i; + return other; + } + bool operator==(const const_iterator &other) const { return (_a == other._a) && (_i == other._i); } + bool operator!=(const const_iterator &other) const { return (_i != other._i) || (_a != other._a); } + const B &operator*() const { return (*_a)[_i]; } + const B *operator->() const { return &(*_a)[_i]; } + size_t operator-(const const_iterator &b) const { return _i - b._i; } + private: + const IArrayT *_a; + size_t _i; + }; + + typedef std::unique_ptr<IArrayT> UP; + virtual const B &operator[](size_t i) const = 0; + virtual B &operator[](size_t i) = 0; + virtual IArrayT *clone() const override = 0; + virtual iterator erase(iterator it) = 0; + virtual const_iterator begin() const { return const_iterator(*this, 0); } + virtual const_iterator end() const { return const_iterator(*this, size()); } + virtual iterator begin() { return iterator(*this, 0); } + virtual iterator end() { return iterator(*this, size()); } + virtual void push_back(const B &v) = 0; +}; + +} diff --git a/staging_vespalib/src/vespa/vespalib/util/polymorphicarraybase.h b/staging_vespalib/src/vespa/vespalib/util/polymorphicarraybase.h new file mode 100644 index 00000000000..0fccd6cabb7 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/util/polymorphicarraybase.h @@ -0,0 +1,18 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// +#pragma once + +namespace vespalib { + +class IArrayBase { +public: + virtual ~IArrayBase() {} + virtual void resize(size_t sz) = 0; + virtual void reserve(size_t sz) = 0; + virtual void clear() = 0; + virtual IArrayBase *clone() const = 0; + virtual size_t size() const = 0; + bool empty() const { return size() == 0; } +}; + +} diff --git a/staging_vespalib/src/vespa/vespalib/util/polymorphicarrays.h b/staging_vespalib/src/vespa/vespalib/util/polymorphicarrays.h index 98c9d271ea2..646ca522ba3 100644 --- a/staging_vespalib/src/vespa/vespalib/util/polymorphicarrays.h +++ b/staging_vespalib/src/vespa/vespalib/util/polymorphicarrays.h @@ -2,76 +2,12 @@ // #pragma once +#include "polymorphicarray.h" #include <vespa/vespalib/util/memory.h> #include <vector> namespace vespalib { -/** - * Describes an interface an array of polymorphic types. - * The intention is to allow efficient implementations when that is possible - * while still enjoying the flexibility of the polymorph interface. - * It is not a full feldged Array implementation as std::vector. It contains just - * the minimum required to allow for efficient implementations for document::ArrayFieldValue. - * - * You specify the base type the interface shall provide. This base type must define - * virtual void assign(const B & rhs); - * For use with ComplexArrayT your type also need - * virtual T * clone() const; - */ -template<typename B> -class IArrayT -{ -public: - class iterator { - public: - iterator(IArrayT & a, size_t i) : _a(&a), _i(i) { } - iterator operator+(size_t diff) const { return iterator(*_a, _i + diff); } - iterator& operator++() { ++_i; return *this; } - iterator operator++(int) { iterator other(*this); ++_i; return other; } - bool operator==(const iterator & other) const { return (_a == other._a) && (_i == other._i); } - bool operator!=(const iterator & other) const { return (_i != other._i) || (_a != other._a); } - B & operator*() { return (*_a)[_i]; } - B * operator->() { return &(*_a)[_i]; } - friend ssize_t operator - (const iterator & a, const iterator & b) { return a._i - b._i; } - private: - IArrayT * _a; - size_t _i; - }; - class const_iterator { - public: - const_iterator(const IArrayT & a, size_t i) : _a(&a), _i(i) { } - const_iterator operator+(size_t diff) const { return const_iterator(*_a, _i + diff); } - const_iterator& operator++() { ++_i; return *this; } - const_iterator operator++(int) { const_iterator other(*this); ++_i; return other; } - bool operator==(const const_iterator & other) const { return (_a == other._a) && (_i == other._i); } - bool operator!=(const const_iterator & other) const { return (_i != other._i) || (_a != other._a); } - const B & operator*() const { return (*_a)[_i]; } - const B * operator->() const { return &(*_a)[_i]; } - size_t operator - (const const_iterator & b) const { return _i - b._i; } - private: - const IArrayT * _a; - size_t _i; - }; - typedef std::unique_ptr<IArrayT> UP; - - virtual ~IArrayT() { } - virtual const B & operator [] (size_t i) const = 0; - virtual B & operator [] (size_t i) = 0; - virtual void resize(size_t sz) = 0; - virtual void reserve(size_t sz) = 0; - virtual void clear() = 0; - virtual IArrayT * clone() const = 0; - virtual size_t size() const = 0; - virtual iterator erase(iterator it) = 0; - virtual const_iterator begin() const { return const_iterator(*this, 0); } - virtual const_iterator end() const { return const_iterator(*this, size()); } - virtual iterator begin() { return iterator(*this, 0); } - virtual iterator end() { return iterator(*this, size()); } - bool empty() const { return size() == 0; } - virtual void push_back(const B & v) = 0; -}; - template <typename T, typename B> class PrimitiveArrayT : public IArrayT<B> { diff --git a/staging_vespalib/src/vespa/vespalib/util/xmlserializable.cpp b/staging_vespalib/src/vespa/vespalib/util/xmlserializable.cpp index 043cddc3259..357b3d94992 100644 --- a/staging_vespalib/src/vespa/vespalib/util/xmlserializable.cpp +++ b/staging_vespalib/src/vespa/vespalib/util/xmlserializable.cpp @@ -1,449 +1,12 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include "xmlserializable.hpp" -#include <vespa/vespalib/encoding/base64.h> -#include <vespa/vespalib/stllike/asciistream.h> -#include <vespa/vespalib/util/stringfmt.h> -#include <cassert> +#include "xmlserializable.h" +#include "xmlstream.h" +#include <sstream> namespace vespalib { namespace xml { -namespace { - - std::vector<bool> getLegalIdentifierFirstCharacters() { - std::vector<bool> vec(256, false); - for (uint32_t i='a'; i<='z'; ++i) vec[i] = true; - for (uint32_t i='A'; i<='Z'; ++i) vec[i] = true; - vec[':'] = true; - vec['_'] = true; - return vec; - } - - std::vector<bool> getLegalIdentifierCharacters() { - std::vector<bool> vec(getLegalIdentifierFirstCharacters()); - vec['-'] = true; - vec['.'] = true; - for (uint32_t i='0'; i<='9'; ++i) { - vec[i] = true; - } - return vec; - } - - std::vector<bool> getBinaryCharacters() { - std::vector<bool> vec(256, false); - for (uint32_t i=0; i<32; ++i) { - vec[i] = true; - } - vec['\t'] = false; - vec['\n'] = false; - vec['\r'] = false; - vec['\f'] = false; - return vec; - } - - std::vector<bool> getEscapedXmlCharacters() { - std::vector<bool> vec(256, false); - for (uint32_t i=0; i<32; ++i) { - vec[i] = true; - } - vec['\n'] = false; - vec['<'] = true; - vec['>'] = true; - vec['&'] = true; - return vec; - } - - std::vector<bool> legalIdentifierFirstChar( - getLegalIdentifierFirstCharacters()); - std::vector<bool> legalIdentifierChars = getLegalIdentifierCharacters(); - std::vector<bool> binaryChars = getBinaryCharacters(); - std::vector<bool> escapedXmlChars = getEscapedXmlCharacters(); - - bool containsBinaryCharacters(const std::string& s) { - for (int i=0, n=s.size(); i<n; ++i) { - if (binaryChars[static_cast<uint8_t>(s[i])]) return true; - } - return false; - } - - const std::string xmlAttributeEscape(const std::string& s) { - vespalib::asciistream ost; - for (uint32_t i=0, n=s.size(); i<n; ++i) { - if (s[i] == '"' || s[i] == '\n' - || escapedXmlChars[static_cast<uint8_t>(s[i])]) - { - if (s[i] == '<') ost << "<"; - else if (s[i] == '>') ost << ">"; - else if (s[i] == '&') ost << "&"; - else if (s[i] == '"') ost << """; - else { - ost << "&#" << (int) s[i] << ";"; - } - } else { - ost << s[i]; - } - } - return ost.str(); - } - - void writeEscaped(std::ostream& out, const std::string& s) { - for (uint32_t i=0, n=s.size(); i<n; ++i) { - if (escapedXmlChars[static_cast<uint8_t>(s[i])]) { - if (s[i] == '<') out << "<"; - else if (s[i] == '>') out << ">"; - else if (s[i] == '&') out << "&"; - else { - out << "&#" << (int) s[i] << ";"; - } - } else { - out << s[i]; - } - } - } - - void writeBase64Encoded(std::ostream& out, const std::string& s) { - out << vespalib::Base64::encode(&s[0], s.size()); - } -} - -bool isLegalName(const std::string& name) { - if (name.size() == 0) return false; - if (!legalIdentifierFirstChar[static_cast<uint8_t>(name[0])]) return false; - for (int i=1, n=name.size(); i<n; ++i) { - if (!legalIdentifierChars[static_cast<uint8_t>(name[i])]) return false; - } - return true; -} - -void convertToLegalName(std::string& name) { - if (name.size() == 0) { - name == "__no_name__"; - } else { - if (!legalIdentifierFirstChar[static_cast<uint8_t>(name[0])]) { - name[0] = '_'; - } - for (int i=1, n=name.size(); i<n; ++i) { - if (!legalIdentifierChars[static_cast<uint8_t>(name[i])]) { - name[i] = '_'; - } - } - } -} - -XmlOutputStream::XmlOutputStream(std::ostream& ostream, - const std::string& indent) - : _indent(indent), - _wrappedStream(ostream), - _tagStack(), - _cachedTag(), - _cachedAttributes(), - _cachedContent() -{ -} - -XmlAttribute::~XmlAttribute() -{ -} - -XmlContent::~XmlContent() -{ -} - -XmlOutputStream::~XmlOutputStream() -{ -} - -XmlOutputStream& -XmlOutputStream::operator<<(const XmlTag& tag) -{ - //std::cerr << "Trying to add tag " << tag.getName() << ". cached tag is " - // << (void*) _cachedTag.get() << "\n"; - if (_cachedTag.get() != 0) flush(false); - _cachedTag.reset(new XmlTag(tag)); - _cachedContentType = XmlContent::AUTO; - //std::cerr << "Added tag " << _cachedTag->getName() << "\n"; - return *this; -} - -XmlOutputStream& -XmlOutputStream::operator<<(const XmlAttribute& attribute) -{ - //std::cerr << "Adding attribute\n"; - if (_cachedTag.get() == 0) { - throw vespalib::IllegalStateException("Cannot add attribute " - + attribute.getName() + ", as no tag is open"); - } - _cachedAttributes.push_back(attribute); - return *this; -} - -XmlOutputStream& -XmlOutputStream::operator<<(const XmlEndTag&) -{ - //std::cerr << "Adding endtag\n"; - if (_cachedTag.get()) { - flush(true); - _cachedContentType = XmlContent::ESCAPED; - } else if (_tagStack.empty()) { - throw vespalib::IllegalStateException("No open tags left to end"); - } else { - for (uint32_t i=1; i<_tagStack.size(); ++i) { - _wrappedStream << _indent; - } - _wrappedStream << "</" << _tagStack.back() << ">"; - _tagStack.pop_back(); - if (!_tagStack.empty()) _wrappedStream << '\n'; - _cachedContentType = XmlContent::ESCAPED; - } - return *this; -} - -XmlOutputStream& -XmlOutputStream::operator<<(const XmlContent& content) -{ - //std::cerr << "Adding content\n"; - if (_cachedTag.get() == 0 && _tagStack.empty()) { - throw vespalib::IllegalStateException( - "No open tag to write content in"); - } - if (_cachedTag.get() != 0) { - //std::cerr << "Content is '" << content.getContent() << "'\n"; - if (content.getType() == XmlContent::AUTO) { // Do nothing.. Always ok - } else if (_cachedContentType == XmlContent::AUTO) { - _cachedContentType = content.getType(); - } else if (_cachedContentType != content.getType()) { - throw vespalib::IllegalStateException( - "Have already added content of different type"); - } - _cachedContent.push_back(content); - } else { - if (content.getType() == XmlContent::BASE64) { - throw vespalib::IllegalStateException( - "Cannot add Base64 encoded content after tag content"); - } - for (uint32_t i=0; i<_tagStack.size(); ++i) { - _wrappedStream << _indent; - } - _wrappedStream << content.getContent() << '\n'; - } - return *this; -} - -XmlOutputStream& -XmlOutputStream::operator<<(const XmlSerializable& serializable) -{ - //std::cerr << "Adding serializable\n"; - serializable.printXml(*this); - return *this; -} - -XmlOutputStream& -XmlOutputStream::operator<<(const std::string& content) -{ - //std::cerr << "Adding content string\n"; - return *this << XmlContent(content); -} - -XmlOutputStream& -XmlOutputStream::operator<<(char c) -{ - return *this << XmlContent(std::string(&c, 1)); -} - -XmlOutputStream& -XmlOutputStream::operator<<(int32_t i) -{ - return *this << XmlContent(vespalib::make_string("%d", i)); -} - -XmlOutputStream& -XmlOutputStream::operator<<(int64_t i) -{ - return *this << XmlContent(vespalib::make_string("%" PRId64, i)); -} - -XmlOutputStream& -XmlOutputStream::operator<<(float f) -{ - return *this << XmlContent(vespalib::make_string("%g", f)); -} - -XmlOutputStream& -XmlOutputStream::operator<<(double d) -{ - return *this << XmlContent(vespalib::make_string("%g", d)); -} - -void -XmlOutputStream::flush(bool endTag) -{ - //std::cerr << "Flushing\n"; - if (_cachedTag.get() == 0) { - throw vespalib::IllegalStateException("Cannot write non-existing tag"); - } - for (uint32_t i=0; i<_tagStack.size(); ++i) { - _wrappedStream << _indent; - } - _wrappedStream << '<' << _cachedTag->getName(); - for (std::list<XmlAttribute>::const_iterator it = _cachedAttributes.begin(); - it != _cachedAttributes.end(); ++it) - { - _wrappedStream << ' ' << it->getName() << "=\"" - << xmlAttributeEscape(it->getValue()) << '"'; - } - _cachedAttributes.clear(); - if (_cachedContent.empty() && endTag) { - _wrappedStream << "/>\n"; - } else if (_cachedContent.empty()) { - _wrappedStream << ">\n"; - _tagStack.push_back(_cachedTag->getName()); - } else { - if (_cachedContentType == XmlContent::AUTO) { - _cachedContentType = XmlContent::ESCAPED; - for (std::list<XmlContent>::const_iterator it - = _cachedContent.begin(); it != _cachedContent.end(); ++it) - { - if (containsBinaryCharacters(it->getContent())) { - _cachedContentType = XmlContent::BASE64; - break; - } - } - } - if (_cachedContentType == XmlContent::BASE64) { - _wrappedStream << " binaryencoding=\"base64\""; - } - _wrappedStream << '>'; - for (std::list<XmlContent>::const_iterator it = _cachedContent.begin(); - it != _cachedContent.end(); ++it) - { - if (!endTag) { - _wrappedStream << '\n'; - for (uint32_t i=0; i<=_tagStack.size(); ++i) { - _wrappedStream << _indent; - } - } - switch (_cachedContentType) { - case XmlContent::ESCAPED: { - writeEscaped(_wrappedStream, it->getContent()); - break; - } - case XmlContent::BASE64: { - writeBase64Encoded(_wrappedStream, it->getContent()); - break; - } - default: assert(false); - } - } - _cachedContent.clear(); - if (endTag) { - _wrappedStream << "</" << _cachedTag->getName() << ">\n"; - } else { - _wrappedStream << '\n'; - _tagStack.push_back(_cachedTag->getName()); - } - } - _cachedTag.reset(0); -} - -XmlTag::XmlTag(const XmlTag& tag) - : _name(tag._name), - _attributes(), - _content(), - _flags(tag._flags) -{ -} - -XmlTag::~XmlTag() {} - -XmlTag::XmlTag(const std::string& name, XmlTagFlags flags) - : _name(name), - _attributes(), - _content(), - _flags(flags) -{ - if (_flags == CONVERT_ILLEGAL_CHARACTERS) { - convertToLegalName(_name); - } - if (!isLegalName(_name)) { - throw vespalib::IllegalArgumentException("Name '" + _name + "' contains " - "illegal XML characters and cannot be used as tag name"); - } -} - -XmlAttribute::XmlAttribute(const XmlAttribute& attribute) - : _name(attribute._name), - _value(attribute._value), - _next() -{ -} - -XmlAttribute::XmlAttribute(const std::string& name, const char * value, uint32_t flags) - : _name(name), - _value(), - _next() -{ - vespalib::asciistream ost; - if (flags & HEX) ost << vespalib::hex << "0x"; - ost << value; - _value = ost.str(); - if (!isLegalName(name)) { - throw vespalib::IllegalArgumentException("Name '" + name + "' contains " - "illegal XML characters and cannot be used as attribute name"); - } -} - -XmlEndTag::XmlEndTag() -{ -} - -XmlContent::XmlContent(Type type) - : _type(type), - _content(), - _nextContent(), - _nextTag() -{ -} - -XmlContent::XmlContent() - : _type(AUTO), - _content(), - _nextContent(), - _nextTag() -{ -} - -XmlContent::XmlContent(const XmlContent& content) - : _type(content._type), - _content(content._content), - _nextContent(), - _nextTag() -{ -} - -XmlContent::XmlContent(const std::string& value) - : _type(AUTO), - _content(value), - _nextContent(), - _nextTag() -{ -} - -XmlContentWrapper::XmlContentWrapper(const XmlContentWrapper& wrapper) - : XmlContent(wrapper) -{ -} - -XmlContentWrapper::XmlContentWrapper(const char* value) - : XmlContent(std::string(value)) -{ -} - -XmlContentWrapper::XmlContentWrapper(const char* value, uint32_t size) - : XmlContent(std::string(value, size)) -{ -} - std::string XmlSerializable::toXml(const std::string& indent) const { @@ -452,22 +15,6 @@ XmlSerializable::toXml(const std::string& indent) const printXml(xos); return ost.str(); } -using CharP = char *; -using ConstCharP = const char *; - -template XmlAttribute::XmlAttribute(const std::string &, const std::string &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const vespalib::string &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const vespalib::stringref &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const CharP &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const ConstCharP &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const bool &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const int16_t &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const int32_t &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const int64_t &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const uint16_t &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const uint32_t &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const uint64_t &, unsigned int); -template XmlAttribute::XmlAttribute(const std::string &, const double &, unsigned int); } // xml } // vespalib diff --git a/staging_vespalib/src/vespa/vespalib/util/xmlserializable.h b/staging_vespalib/src/vespa/vespalib/util/xmlserializable.h index b688c699d76..a4ddb12ed8d 100644 --- a/staging_vespalib/src/vespa/vespalib/util/xmlserializable.h +++ b/staging_vespalib/src/vespa/vespalib/util/xmlserializable.h @@ -1,166 +1,14 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -/** - * @file xmlserializable.h - * @ingroup util - * - * @brief Interfaces to be used for XML serialization. - * - * This file contains XML utility classes, to make XML serialization simple. - * Rather than users writing their own XML, these tools let you define a tree - * structure, and this library builds the XML for you. This ensures that you - * write legal XML and that stuff that needs to be escaped is. - * <p> - * It defines a superclass for XML serializable classes, called XmlSerializable. - * This is what classes that should be XML serializable will inherit. - * <p> - * When implementing the printXml() function in XmlSerializable, one will - * use the various XML helper classes defined here to build a tree structure - * creating the XML. These are: XmlTag, XmlEndTag, XmlAttribute, and XmlContent. - * Some subclasses exist of XmlContent to facilitate various types of content. - * <p> - * The XmlOutputStream wraps a regular std::ostream. You write XML objects to it - * and it is responsible for writing all the XML code. This way, the XML - * serialization is done without interfering with regular output operators. - * <p> - * For example usage, refer to the unit test: - * vespalib/tests/xmlserializable/xmlserializabletest.cpp - * - */ #pragma once -#include <iosfwd> -#include <list> -#include <memory> +#include <string> namespace vespalib { namespace xml { -class XmlAttribute; -class XmlContent; class XmlOutputStream; -bool isLegalName(const std::string& name); - -enum XmlTagFlags { NONE = 0, CONVERT_ILLEGAL_CHARACTERS = 1 }; - -/** - * @class document::XmlTag - * - * @brief Start a new tag with given name. - */ -class XmlTag { - std::string _name; - std::unique_ptr<XmlAttribute> _attributes; - std::unique_ptr<XmlContent> _content; - XmlTagFlags _flags; -public: - XmlTag(const XmlTag&); - XmlTag(const std::string& name, XmlTagFlags = NONE); - ~XmlTag(); - - const std::string& getName() const { return _name; } -}; - -/** - * @class document::XmlEndTag - * - * @brief Indicates that current tag is closed. - */ -class XmlEndTag { -public: - XmlEndTag(); -}; - -/** - * @class document::XmlAttribute - * - * @brief Defined a single attribute within an XML tag. - * - * When adding an XML to an XML stream, the attribute will be added to the last - * tag added. This can not be called after the last tag opened in the stream is - * closed, so add all attributes before starting to add new XML child tags. - */ -class XmlAttribute { - std::string _name; - std::string _value; - std::unique_ptr<XmlAttribute> _next; -public: - enum Flag { NONE = 0x0, HEX = 0x1 }; - XmlAttribute(const XmlAttribute&); - /** Add any value that can be written to an ostringstream. */ - template<typename T> - XmlAttribute(const std::string& name, const T& value, uint32_t flags = NONE); - XmlAttribute(const std::string& name, const char * value, uint32_t flags = NONE); - ~XmlAttribute(); - - const std::string& getName() const { return _name; } - const std::string& getValue() const { return _value; } -}; - - -/** - * @class document::XmlContent - * - * XML content to be written to stream. By default it will autodetect whether to - * escape or base64 encode content. XmlOutputStream functions taking primitives - * will generate XmlContent instances. - */ -class XmlContent { -public: - enum Type { AUTO, ESCAPED, BASE64 }; -protected: - XmlContent(Type type); -private: - Type _type; - std::string _content; - std::unique_ptr<XmlContent> _nextContent; - std::unique_ptr<XmlTag> _nextTag; - -public: - XmlContent(); - XmlContent(const XmlContent&); - XmlContent(const std::string& value); - ~XmlContent(); - - Type getType() const { return _type; } - const std::string& getContent() const { return _content; } -}; - -/** - * @class document::XmlEscapedContent - * - * Token used to tell that this content field should only be XML escaped. - */ -class XmlEscapedContent : public XmlContent { -public: - XmlEscapedContent() : XmlContent(ESCAPED) {} -}; - -/** - * @class document::XmlBase64Content - * - * Token used to tell that this content field should always be base64 encoded. - */ -class XmlBase64Content : public XmlContent { -public: - XmlBase64Content() : XmlContent(BASE64) {} -}; - -/** - * @class document::XmlContentWrapper - * - * A wrapper class for content that one doesn't want to copy or release - * ownership of. This wrapper merely takes pointer to data, and assumes it - * will stay alive as long as needed. - */ -class XmlContentWrapper : public XmlContent { -public: - XmlContentWrapper(const XmlContentWrapper&); - XmlContentWrapper(const char* value); - XmlContentWrapper(const char* value, uint32_t size); -}; - /** * @class document::XmlSerializable * @@ -178,51 +26,6 @@ public: virtual std::string toXml(const std::string& indent = "") const; }; -/** - * @class document::XmlOutputStream - * - * @brief std::ostream wrapper, only accepting data that will become XML. - * - * After XmlEndTag() has been sent to the stream, the tag is guarantueed to have - * been written. Call isFinalized() to ensure that you have closed all the tags - * that have been opened. Within a tag, the stream will cache some information, - * as more information might be required before knowing what to print. - */ -class XmlOutputStream { - const std::string _indent; - std::ostream& _wrappedStream; - std::list<std::string> _tagStack; - std::unique_ptr<XmlTag> _cachedTag; - std::list<XmlAttribute> _cachedAttributes; - std::list<XmlContent> _cachedContent; - XmlContent::Type _cachedContentType; - - void flush(bool endTag); - -public: - - XmlOutputStream(std::ostream& ostream, const std::string& indent = ""); - ~XmlOutputStream(); - - bool isFinalized() const - { return (_tagStack.empty() && _cachedTag.get() == 0); } - - std::ostream& getWrappedStream() { return _wrappedStream; } - - XmlOutputStream& operator<<(const XmlTag& tag); - XmlOutputStream& operator<<(const XmlAttribute& attribute); - XmlOutputStream& operator<<(const XmlEndTag& endtag); - XmlOutputStream& operator<<(const XmlContent& content); - XmlOutputStream& operator<<(const XmlSerializable& serializable); - - XmlOutputStream& operator<<(const std::string& content); - XmlOutputStream& operator<<(char c); - XmlOutputStream& operator<<(int32_t i); - XmlOutputStream& operator<<(int64_t i); - XmlOutputStream& operator<<(float f); - XmlOutputStream& operator<<(double d); -}; - } // xml // The XmlSerializable and XmlOutputStream is often used in header files @@ -230,8 +33,8 @@ public: // vespalib namespace with all the other classes, use // "using namespace vespalib::xml" within your printXml functions -typedef vespalib::xml::XmlOutputStream XmlOutputStream; -typedef vespalib::xml::XmlSerializable XmlSerializable; +using XmlSerializable = vespalib::xml::XmlSerializable; +using XmlOutputStream = vespalib::xml::XmlOutputStream; } // vespalib diff --git a/staging_vespalib/src/vespa/vespalib/util/xmlstream.cpp b/staging_vespalib/src/vespa/vespalib/util/xmlstream.cpp new file mode 100644 index 00000000000..16fce61ddd1 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/util/xmlstream.cpp @@ -0,0 +1,463 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "xmlstream.hpp" +#include <vespa/vespalib/encoding/base64.h> +#include <vespa/vespalib/stllike/asciistream.h> +#include <vespa/vespalib/util/stringfmt.h> +#include <cassert> + +namespace vespalib::xml { + +namespace { + + std::vector<bool> getLegalIdentifierFirstCharacters() { + std::vector<bool> vec(256, false); + for (uint32_t i='a'; i<='z'; ++i) vec[i] = true; + for (uint32_t i='A'; i<='Z'; ++i) vec[i] = true; + vec[':'] = true; + vec['_'] = true; + return vec; + } + + std::vector<bool> getLegalIdentifierCharacters() { + std::vector<bool> vec(getLegalIdentifierFirstCharacters()); + vec['-'] = true; + vec['.'] = true; + for (uint32_t i='0'; i<='9'; ++i) { + vec[i] = true; + } + return vec; + } + + std::vector<bool> getBinaryCharacters() { + std::vector<bool> vec(256, false); + for (uint32_t i=0; i<32; ++i) { + vec[i] = true; + } + vec['\t'] = false; + vec['\n'] = false; + vec['\r'] = false; + vec['\f'] = false; + return vec; + } + + std::vector<bool> getEscapedXmlCharacters() { + std::vector<bool> vec(256, false); + for (uint32_t i=0; i<32; ++i) { + vec[i] = true; + } + vec['\n'] = false; + vec['<'] = true; + vec['>'] = true; + vec['&'] = true; + return vec; + } + + std::vector<bool> legalIdentifierFirstChar( + getLegalIdentifierFirstCharacters()); + std::vector<bool> legalIdentifierChars = getLegalIdentifierCharacters(); + std::vector<bool> binaryChars = getBinaryCharacters(); + std::vector<bool> escapedXmlChars = getEscapedXmlCharacters(); + + bool containsBinaryCharacters(const std::string& s) { + for (int i=0, n=s.size(); i<n; ++i) { + if (binaryChars[static_cast<uint8_t>(s[i])]) return true; + } + return false; + } + + const std::string xmlAttributeEscape(const std::string& s) { + vespalib::asciistream ost; + for (uint32_t i=0, n=s.size(); i<n; ++i) { + if (s[i] == '"' || s[i] == '\n' + || escapedXmlChars[static_cast<uint8_t>(s[i])]) + { + if (s[i] == '<') ost << "<"; + else if (s[i] == '>') ost << ">"; + else if (s[i] == '&') ost << "&"; + else if (s[i] == '"') ost << """; + else { + ost << "&#" << (int) s[i] << ";"; + } + } else { + ost << s[i]; + } + } + return ost.str(); + } + + void writeEscaped(std::ostream& out, const std::string& s) { + for (uint32_t i=0, n=s.size(); i<n; ++i) { + if (escapedXmlChars[static_cast<uint8_t>(s[i])]) { + if (s[i] == '<') out << "<"; + else if (s[i] == '>') out << ">"; + else if (s[i] == '&') out << "&"; + else { + out << "&#" << (int) s[i] << ";"; + } + } else { + out << s[i]; + } + } + } + + void writeBase64Encoded(std::ostream& out, const std::string& s) { + out << vespalib::Base64::encode(&s[0], s.size()); + } +} + +bool isLegalName(const std::string& name) { + if (name.size() == 0) return false; + if (!legalIdentifierFirstChar[static_cast<uint8_t>(name[0])]) return false; + for (int i=1, n=name.size(); i<n; ++i) { + if (!legalIdentifierChars[static_cast<uint8_t>(name[i])]) return false; + } + return true; +} + +void convertToLegalName(std::string& name) { + if (name.size() == 0) { + name == "__no_name__"; + } else { + if (!legalIdentifierFirstChar[static_cast<uint8_t>(name[0])]) { + name[0] = '_'; + } + for (int i=1, n=name.size(); i<n; ++i) { + if (!legalIdentifierChars[static_cast<uint8_t>(name[i])]) { + name[i] = '_'; + } + } + } +} + +XmlOutputStream::XmlOutputStream(std::ostream& ostream, + const std::string& indent) + : _indent(indent), + _wrappedStream(ostream), + _tagStack(), + _cachedTag(), + _cachedAttributes(), + _cachedContent() +{ +} + +XmlAttribute::~XmlAttribute() +{ +} + +XmlContent::~XmlContent() +{ +} + +XmlOutputStream::~XmlOutputStream() +{ +} + +XmlOutputStream& +XmlOutputStream::operator<<(const XmlTag& tag) +{ + //std::cerr << "Trying to add tag " << tag.getName() << ". cached tag is " + // << (void*) _cachedTag.get() << "\n"; + if (_cachedTag.get() != 0) flush(false); + _cachedTag.reset(new XmlTag(tag)); + _cachedContentType = XmlContent::AUTO; + //std::cerr << "Added tag " << _cachedTag->getName() << "\n"; + return *this; +} + +XmlOutputStream& +XmlOutputStream::operator<<(const XmlAttribute& attribute) +{ + //std::cerr << "Adding attribute\n"; + if (_cachedTag.get() == 0) { + throw vespalib::IllegalStateException("Cannot add attribute " + + attribute.getName() + ", as no tag is open"); + } + _cachedAttributes.push_back(attribute); + return *this; +} + +XmlOutputStream& +XmlOutputStream::operator<<(const XmlEndTag&) +{ + //std::cerr << "Adding endtag\n"; + if (_cachedTag.get()) { + flush(true); + _cachedContentType = XmlContent::ESCAPED; + } else if (_tagStack.empty()) { + throw vespalib::IllegalStateException("No open tags left to end"); + } else { + for (uint32_t i=1; i<_tagStack.size(); ++i) { + _wrappedStream << _indent; + } + _wrappedStream << "</" << _tagStack.back() << ">"; + _tagStack.pop_back(); + if (!_tagStack.empty()) _wrappedStream << '\n'; + _cachedContentType = XmlContent::ESCAPED; + } + return *this; +} + +XmlOutputStream& +XmlOutputStream::operator<<(const XmlContent& content) +{ + //std::cerr << "Adding content\n"; + if (_cachedTag.get() == 0 && _tagStack.empty()) { + throw vespalib::IllegalStateException( + "No open tag to write content in"); + } + if (_cachedTag.get() != 0) { + //std::cerr << "Content is '" << content.getContent() << "'\n"; + if (content.getType() == XmlContent::AUTO) { // Do nothing.. Always ok + } else if (_cachedContentType == XmlContent::AUTO) { + _cachedContentType = content.getType(); + } else if (_cachedContentType != content.getType()) { + throw vespalib::IllegalStateException( + "Have already added content of different type"); + } + _cachedContent.push_back(content); + } else { + if (content.getType() == XmlContent::BASE64) { + throw vespalib::IllegalStateException( + "Cannot add Base64 encoded content after tag content"); + } + for (uint32_t i=0; i<_tagStack.size(); ++i) { + _wrappedStream << _indent; + } + _wrappedStream << content.getContent() << '\n'; + } + return *this; +} + +XmlOutputStream& +XmlOutputStream::operator<<(const XmlSerializable& serializable) +{ + //std::cerr << "Adding serializable\n"; + serializable.printXml(*this); + return *this; +} + +XmlOutputStream& +XmlOutputStream::operator<<(const std::string& content) +{ + //std::cerr << "Adding content string\n"; + return *this << XmlContent(content); +} + +XmlOutputStream& +XmlOutputStream::operator<<(char c) +{ + return *this << XmlContent(std::string(&c, 1)); +} + +XmlOutputStream& +XmlOutputStream::operator<<(int32_t i) +{ + return *this << XmlContent(vespalib::make_string("%d", i)); +} + +XmlOutputStream& +XmlOutputStream::operator<<(int64_t i) +{ + return *this << XmlContent(vespalib::make_string("%" PRId64, i)); +} + +XmlOutputStream& +XmlOutputStream::operator<<(float f) +{ + return *this << XmlContent(vespalib::make_string("%g", f)); +} + +XmlOutputStream& +XmlOutputStream::operator<<(double d) +{ + return *this << XmlContent(vespalib::make_string("%g", d)); +} + +void +XmlOutputStream::flush(bool endTag) +{ + //std::cerr << "Flushing\n"; + if (_cachedTag.get() == 0) { + throw vespalib::IllegalStateException("Cannot write non-existing tag"); + } + for (uint32_t i=0; i<_tagStack.size(); ++i) { + _wrappedStream << _indent; + } + _wrappedStream << '<' << _cachedTag->getName(); + for (std::list<XmlAttribute>::const_iterator it = _cachedAttributes.begin(); + it != _cachedAttributes.end(); ++it) + { + _wrappedStream << ' ' << it->getName() << "=\"" + << xmlAttributeEscape(it->getValue()) << '"'; + } + _cachedAttributes.clear(); + if (_cachedContent.empty() && endTag) { + _wrappedStream << "/>\n"; + } else if (_cachedContent.empty()) { + _wrappedStream << ">\n"; + _tagStack.push_back(_cachedTag->getName()); + } else { + if (_cachedContentType == XmlContent::AUTO) { + _cachedContentType = XmlContent::ESCAPED; + for (std::list<XmlContent>::const_iterator it + = _cachedContent.begin(); it != _cachedContent.end(); ++it) + { + if (containsBinaryCharacters(it->getContent())) { + _cachedContentType = XmlContent::BASE64; + break; + } + } + } + if (_cachedContentType == XmlContent::BASE64) { + _wrappedStream << " binaryencoding=\"base64\""; + } + _wrappedStream << '>'; + for (std::list<XmlContent>::const_iterator it = _cachedContent.begin(); + it != _cachedContent.end(); ++it) + { + if (!endTag) { + _wrappedStream << '\n'; + for (uint32_t i=0; i<=_tagStack.size(); ++i) { + _wrappedStream << _indent; + } + } + switch (_cachedContentType) { + case XmlContent::ESCAPED: { + writeEscaped(_wrappedStream, it->getContent()); + break; + } + case XmlContent::BASE64: { + writeBase64Encoded(_wrappedStream, it->getContent()); + break; + } + default: assert(false); + } + } + _cachedContent.clear(); + if (endTag) { + _wrappedStream << "</" << _cachedTag->getName() << ">\n"; + } else { + _wrappedStream << '\n'; + _tagStack.push_back(_cachedTag->getName()); + } + } + _cachedTag.reset(0); +} + +XmlTag::XmlTag(const XmlTag& tag) + : _name(tag._name), + _attributes(), + _content(), + _flags(tag._flags) +{ +} + +XmlTag::~XmlTag() {} + +XmlTag::XmlTag(const std::string& name, XmlTagFlags flags) + : _name(name), + _attributes(), + _content(), + _flags(flags) +{ + if (_flags == CONVERT_ILLEGAL_CHARACTERS) { + convertToLegalName(_name); + } + if (!isLegalName(_name)) { + throw vespalib::IllegalArgumentException("Name '" + _name + "' contains " + "illegal XML characters and cannot be used as tag name"); + } +} + +XmlAttribute::XmlAttribute(const XmlAttribute& attribute) + : _name(attribute._name), + _value(attribute._value), + _next() +{ +} + +XmlAttribute::XmlAttribute(const std::string& name, const char * value, uint32_t flags) + : _name(name), + _value(), + _next() +{ + vespalib::asciistream ost; + if (flags & HEX) ost << vespalib::hex << "0x"; + ost << value; + _value = ost.str(); + if (!isLegalName(name)) { + throw vespalib::IllegalArgumentException("Name '" + name + "' contains " + "illegal XML characters and cannot be used as attribute name"); + } +} + +XmlEndTag::XmlEndTag() +{ +} + +XmlContent::XmlContent(Type type) + : _type(type), + _content(), + _nextContent(), + _nextTag() +{ +} + +XmlContent::XmlContent() + : _type(AUTO), + _content(), + _nextContent(), + _nextTag() +{ +} + +XmlContent::XmlContent(const XmlContent& content) + : _type(content._type), + _content(content._content), + _nextContent(), + _nextTag() +{ +} + +XmlContent::XmlContent(const std::string& value) + : _type(AUTO), + _content(value), + _nextContent(), + _nextTag() +{ +} + +XmlContentWrapper::XmlContentWrapper(const XmlContentWrapper& wrapper) + : XmlContent(wrapper) +{ +} + +XmlContentWrapper::XmlContentWrapper(const char* value) + : XmlContent(std::string(value)) +{ +} + +XmlContentWrapper::XmlContentWrapper(const char* value, uint32_t size) + : XmlContent(std::string(value, size)) +{ +} + +using CharP = char *; +using ConstCharP = const char *; + +template XmlAttribute::XmlAttribute(const std::string &, const std::string &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const vespalib::string &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const vespalib::stringref &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const CharP &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const ConstCharP &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const bool &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const int16_t &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const int32_t &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const int64_t &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const uint16_t &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const uint32_t &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const uint64_t &, unsigned int); +template XmlAttribute::XmlAttribute(const std::string &, const double &, unsigned int); + +} diff --git a/staging_vespalib/src/vespa/vespalib/util/xmlstream.h b/staging_vespalib/src/vespa/vespalib/util/xmlstream.h new file mode 100644 index 00000000000..8ed781e57c3 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/util/xmlstream.h @@ -0,0 +1,210 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/** + * @file xmlserializable.h + * @ingroup util + * + * @brief Interfaces to be used for XML serialization. + * + * This file contains XML utility classes, to make XML serialization simple. + * Rather than users writing their own XML, these tools let you define a tree + * structure, and this library builds the XML for you. This ensures that you + * write legal XML and that stuff that needs to be escaped is. + * <p> + * It defines a superclass for XML serializable classes, called XmlSerializable. + * This is what classes that should be XML serializable will inherit. + * <p> + * When implementing the printXml() function in XmlSerializable, one will + * use the various XML helper classes defined here to build a tree structure + * creating the XML. These are: XmlTag, XmlEndTag, XmlAttribute, and XmlContent. + * Some subclasses exist of XmlContent to facilitate various types of content. + * <p> + * The XmlOutputStream wraps a regular std::ostream. You write XML objects to it + * and it is responsible for writing all the XML code. This way, the XML + * serialization is done without interfering with regular output operators. + * <p> + * For example usage, refer to the unit test: + * vespalib/tests/xmlserializable/xmlserializabletest.cpp + * + */ + +#pragma once + +#include "xmlserializable.h" +#include <iosfwd> +#include <list> +#include <memory> + +namespace vespalib::xml { + +class XmlAttribute; +class XmlContent; +class XmlOutputStream; + +bool isLegalName(const std::string& name); + +enum XmlTagFlags { NONE = 0, CONVERT_ILLEGAL_CHARACTERS = 1 }; + +/** + * @class document::XmlTag + * + * @brief Start a new tag with given name. + */ +class XmlTag { + std::string _name; + std::unique_ptr<XmlAttribute> _attributes; + std::unique_ptr<XmlContent> _content; + XmlTagFlags _flags; +public: + XmlTag(const XmlTag&); + XmlTag(const std::string& name, XmlTagFlags = NONE); + ~XmlTag(); + + const std::string& getName() const { return _name; } +}; + +/** + * @class document::XmlEndTag + * + * @brief Indicates that current tag is closed. + */ +class XmlEndTag { +public: + XmlEndTag(); +}; + +/** + * @class document::XmlAttribute + * + * @brief Defined a single attribute within an XML tag. + * + * When adding an XML to an XML stream, the attribute will be added to the last + * tag added. This can not be called after the last tag opened in the stream is + * closed, so add all attributes before starting to add new XML child tags. + */ +class XmlAttribute { + std::string _name; + std::string _value; + std::unique_ptr<XmlAttribute> _next; +public: + enum Flag { NONE = 0x0, HEX = 0x1 }; + XmlAttribute(const XmlAttribute&); + /** Add any value that can be written to an ostringstream. */ + template<typename T> + XmlAttribute(const std::string& name, const T& value, uint32_t flags = NONE); + XmlAttribute(const std::string& name, const char * value, uint32_t flags = NONE); + ~XmlAttribute(); + + const std::string& getName() const { return _name; } + const std::string& getValue() const { return _value; } +}; + + +/** + * @class document::XmlContent + * + * XML content to be written to stream. By default it will autodetect whether to + * escape or base64 encode content. XmlOutputStream functions taking primitives + * will generate XmlContent instances. + */ +class XmlContent { +public: + enum Type { AUTO, ESCAPED, BASE64 }; +protected: + XmlContent(Type type); +private: + Type _type; + std::string _content; + std::unique_ptr<XmlContent> _nextContent; + std::unique_ptr<XmlTag> _nextTag; + +public: + XmlContent(); + XmlContent(const XmlContent&); + XmlContent(const std::string& value); + ~XmlContent(); + + Type getType() const { return _type; } + const std::string& getContent() const { return _content; } +}; + +/** + * @class document::XmlEscapedContent + * + * Token used to tell that this content field should only be XML escaped. + */ +class XmlEscapedContent : public XmlContent { +public: + XmlEscapedContent() : XmlContent(ESCAPED) {} +}; + +/** + * @class document::XmlBase64Content + * + * Token used to tell that this content field should always be base64 encoded. + */ +class XmlBase64Content : public XmlContent { +public: + XmlBase64Content() : XmlContent(BASE64) {} +}; + +/** + * @class document::XmlContentWrapper + * + * A wrapper class for content that one doesn't want to copy or release + * ownership of. This wrapper merely takes pointer to data, and assumes it + * will stay alive as long as needed. + */ +class XmlContentWrapper : public XmlContent { +public: + XmlContentWrapper(const XmlContentWrapper&); + XmlContentWrapper(const char* value); + XmlContentWrapper(const char* value, uint32_t size); +}; + +/** + * @class document::XmlOutputStream + * + * @brief std::ostream wrapper, only accepting data that will become XML. + * + * After XmlEndTag() has been sent to the stream, the tag is guarantueed to have + * been written. Call isFinalized() to ensure that you have closed all the tags + * that have been opened. Within a tag, the stream will cache some information, + * as more information might be required before knowing what to print. + */ +class XmlOutputStream { + const std::string _indent; + std::ostream& _wrappedStream; + std::list<std::string> _tagStack; + std::unique_ptr<XmlTag> _cachedTag; + std::list<XmlAttribute> _cachedAttributes; + std::list<XmlContent> _cachedContent; + XmlContent::Type _cachedContentType; + + void flush(bool endTag); + +public: + + XmlOutputStream(std::ostream& ostream, const std::string& indent = ""); + ~XmlOutputStream(); + + bool isFinalized() const + { return (_tagStack.empty() && _cachedTag.get() == 0); } + + std::ostream& getWrappedStream() { return _wrappedStream; } + + XmlOutputStream& operator<<(const XmlTag& tag); + XmlOutputStream& operator<<(const XmlAttribute& attribute); + XmlOutputStream& operator<<(const XmlEndTag& endtag); + XmlOutputStream& operator<<(const XmlContent& content); + XmlOutputStream& operator<<(const XmlSerializable& serializable); + + XmlOutputStream& operator<<(const std::string& content); + XmlOutputStream& operator<<(char c); + XmlOutputStream& operator<<(int32_t i); + XmlOutputStream& operator<<(int64_t i); + XmlOutputStream& operator<<(float f); + XmlOutputStream& operator<<(double d); +}; + +} + diff --git a/staging_vespalib/src/vespa/vespalib/util/xmlserializable.hpp b/staging_vespalib/src/vespa/vespalib/util/xmlstream.hpp index 0da684d6b28..243efe9e94b 100644 --- a/staging_vespalib/src/vespa/vespalib/util/xmlserializable.hpp +++ b/staging_vespalib/src/vespa/vespalib/util/xmlstream.hpp @@ -2,12 +2,11 @@ #pragma once -#include "xmlserializable.h" +#include "xmlstream.h" #include <vespa/vespalib/util/exceptions.h> #include <sstream> -namespace vespalib { -namespace xml { +namespace vespalib::xml { template<typename T> XmlAttribute::XmlAttribute(const std::string& name, const T& value, uint32_t flags) @@ -20,10 +19,9 @@ XmlAttribute::XmlAttribute(const std::string& name, const T& value, uint32_t fla ost << value; _value = ost.str(); if (!isLegalName(name)) { - throw vespalib::IllegalArgumentException("Name '" + name + "' contains " + throw IllegalArgumentException("Name '" + name + "' contains " "illegal XML characters and cannot be used as attribute name"); } } } -} diff --git a/storage/src/vespa/storage/bucketdb/bucketmanager.h b/storage/src/vespa/storage/bucketdb/bucketmanager.h index d3a939d90c5..09cbc60b58e 100644 --- a/storage/src/vespa/storage/bucketdb/bucketmanager.h +++ b/storage/src/vespa/storage/bucketdb/bucketmanager.h @@ -25,6 +25,7 @@ #include <vespa/storageapi/message/bucket.h> #include <vespa/config/subscription/configuri.h> #include <unordered_set> +#include <list> namespace storage { diff --git a/storage/src/vespa/storage/bucketdb/storagebucketdbinitializer.h b/storage/src/vespa/storage/bucketdb/storagebucketdbinitializer.h index f56b45c71b3..92c00c4420a 100644 --- a/storage/src/vespa/storage/bucketdb/storagebucketdbinitializer.h +++ b/storage/src/vespa/storage/bucketdb/storagebucketdbinitializer.h @@ -50,6 +50,7 @@ #include <vespa/vespalib/util/sync.h> #include <vespa/vdslib/state/nodestate.h> #include <vespa/config/subscription/configuri.h> +#include <list> namespace storage { diff --git a/storage/src/vespa/storage/common/statusmetricconsumer.cpp b/storage/src/vespa/storage/common/statusmetricconsumer.cpp index 3111508fddc..8cb5c9018f4 100644 --- a/storage/src/vespa/storage/common/statusmetricconsumer.cpp +++ b/storage/src/vespa/storage/common/statusmetricconsumer.cpp @@ -1,20 +1,19 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "statusmetricconsumer.h" - +#include <vespa/storageframework/generic/memory/memorymanagerinterface.h> +#include <vespa/storageframework/generic/status/htmlstatusreporter.h> #include <boost/assign.hpp> #include <boost/lexical_cast.hpp> -#include <vespa/log/log.h> #include <vespa/metrics/printutils.h> #include <vespa/metrics/jsonwriter.h> #include <vespa/metrics/textwriter.h> #include <vespa/metrics/xmlwriter.h> #include <vespa/storageapi/messageapi/storagemessage.h> #include <vespa/vespalib/stllike/asciistream.h> -#include <vespa/storageframework/generic/memory/memorymanagerinterface.h> -#include <vespa/storageframework/generic/status/htmlstatusreporter.h> - +#include <vespa/vespalib/util/xmlstream.h> +#include <vespa/log/log.h> LOG_SETUP(".status.metricreporter"); namespace storage { diff --git a/storage/src/vespa/storage/distributor/bucketdbupdater.cpp b/storage/src/vespa/storage/distributor/bucketdbupdater.cpp index 068f42f8b31..eede73bed63 100644 --- a/storage/src/vespa/storage/distributor/bucketdbupdater.cpp +++ b/storage/src/vespa/storage/distributor/bucketdbupdater.cpp @@ -7,6 +7,7 @@ #include <vespa/storageapi/message/persistence.h> #include <vespa/storageapi/message/removelocation.h> #include <vespa/storageapi/message/multioperation.h> +#include <vespa/vespalib/util/xmlstream.h> #include <vespa/log/log.h> LOG_SETUP(".distributor.bucketdb.updater"); diff --git a/storage/src/vespa/storage/distributor/bucketdbupdater.h b/storage/src/vespa/storage/distributor/bucketdbupdater.h index 3f0989e9b4f..3bd86fc3db6 100644 --- a/storage/src/vespa/storage/distributor/bucketdbupdater.h +++ b/storage/src/vespa/storage/distributor/bucketdbupdater.h @@ -17,6 +17,7 @@ #include <vespa/storageapi/messageapi/messagehandler.h> #include <set> #include <deque> +#include <list> namespace storage::distributor { diff --git a/storage/src/vespa/storage/distributor/pendingclusterstate.cpp b/storage/src/vespa/storage/distributor/pendingclusterstate.cpp index 9497bf05f17..5a2f0d35e8c 100644 --- a/storage/src/vespa/storage/distributor/pendingclusterstate.cpp +++ b/storage/src/vespa/storage/distributor/pendingclusterstate.cpp @@ -4,7 +4,7 @@ #include "bucketdbupdater.h" #include <vespa/storageframework/defaultimplementation/clock/realclock.h> #include <vespa/storage/common/bucketoperationlogger.h> -#include <vespa/vespalib/util/xmlserializable.hpp> +#include <vespa/vespalib/util/xmlstream.hpp> #include <vespa/log/log.h> LOG_SETUP(".pendingclusterstate"); diff --git a/storage/src/vespa/storage/storageserver/bucketintegritychecker.h b/storage/src/vespa/storage/storageserver/bucketintegritychecker.h index 3add8c56e4b..f55cb18366c 100644 --- a/storage/src/vespa/storage/storageserver/bucketintegritychecker.h +++ b/storage/src/vespa/storage/storageserver/bucketintegritychecker.h @@ -16,6 +16,7 @@ #include <vespa/storageapi/message/bucket.h> #include <vespa/storageframework/generic/status/htmlstatusreporter.h> #include <vespa/config/config.h> +#include <list> namespace storage { diff --git a/storageapi/src/vespa/storageapi/buckets/bucketinfo.cpp b/storageapi/src/vespa/storageapi/buckets/bucketinfo.cpp index 07ba2773e91..f9924c953c2 100644 --- a/storageapi/src/vespa/storageapi/buckets/bucketinfo.cpp +++ b/storageapi/src/vespa/storageapi/buckets/bucketinfo.cpp @@ -1,9 +1,9 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "bucketinfo.h" #include <vespa/vespalib/stllike/asciistream.h> +#include <vespa/vespalib/util/xmlstream.h> -namespace storage { -namespace api { +namespace storage::api { BucketInfo::BucketInfo() : _lastModified(0), @@ -124,5 +124,4 @@ BucketInfo::printXml(vespalib::XmlOutputStream& xos) const << XmlAttribute("lastmodified", _lastModified); } -} // api -} // storage +} diff --git a/storageframework/src/vespa/storageframework/generic/status/xmlstatusreporter.h b/storageframework/src/vespa/storageframework/generic/status/xmlstatusreporter.h index 522a6480a75..2f38b89fa15 100644 --- a/storageframework/src/vespa/storageframework/generic/status/xmlstatusreporter.h +++ b/storageframework/src/vespa/storageframework/generic/status/xmlstatusreporter.h @@ -18,7 +18,7 @@ #pragma once #include "statusreporter.h" -#include <vespa/vespalib/util/xmlserializable.h> +#include <vespa/vespalib/util/xmlstream.h> namespace storage::framework { diff --git a/streamingvisitors/src/vespa/searchvisitor/searchvisitor.cpp b/streamingvisitors/src/vespa/searchvisitor/searchvisitor.cpp index 56c95e7fbc7..7b5e5f17671 100644 --- a/streamingvisitors/src/vespa/searchvisitor/searchvisitor.cpp +++ b/streamingvisitors/src/vespa/searchvisitor/searchvisitor.cpp @@ -368,7 +368,7 @@ SearchVisitorFactory::makeVisitor(StorageComponent& component, } void -SearchVisitor::AttributeInserter::onPrimitive(uint32_t, const IteratorContent & c) +SearchVisitor::AttributeInserter::onPrimitive(uint32_t, const Content & c) { const document::FieldValue & value = c.getValue(); LOG(debug, "AttributeInserter: Adding value '%s'(%d) to attribute '%s' for docid '%d'", @@ -402,13 +402,13 @@ SearchVisitor::PositionInserter::PositionInserter(search::AttributeVector & attr SearchVisitor::PositionInserter::~PositionInserter() {} void -SearchVisitor::PositionInserter::onPrimitive(uint32_t, const IteratorContent & c) +SearchVisitor::PositionInserter::onPrimitive(uint32_t, const Content & c) { (void) c; } void -SearchVisitor::PositionInserter::onStructStart(const IteratorContent & c) +SearchVisitor::PositionInserter::onStructStart(const Content & c) { const document::StructuredFieldValue & value = static_cast<const document::StructuredFieldValue &>(c.getValue()); LOG(debug, "PositionInserter: Adding value '%s'(%d) to attribute '%s' for docid '%d'", diff --git a/streamingvisitors/src/vespa/searchvisitor/searchvisitor.h b/streamingvisitors/src/vespa/searchvisitor/searchvisitor.h index 7767a601ea4..47d6157525c 100644 --- a/streamingvisitors/src/vespa/searchvisitor/searchvisitor.h +++ b/streamingvisitors/src/vespa/searchvisitor/searchvisitor.h @@ -27,6 +27,7 @@ #include <vespa/storage/visiting/visitor.h> #include <vespa/document/fieldvalue/fieldvalues.h> #include <vespa/documentapi/messagebus/messages/queryresultmessage.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> using namespace search::aggregation; @@ -86,13 +87,12 @@ private: * This class gets callbacks when iterating through a field value and * inserts the values into a given attribute vector. **/ - class AttributeInserter : public document::FieldValue::IteratorHandler { + class AttributeInserter : public document::fieldvalue::IteratorHandler { protected: - typedef document::FieldValue::IteratorHandler::Content IteratorContent; search::AttributeVector & _attribute; search::AttributeVector::DocId _docId; - void onPrimitive(uint32_t fid, const IteratorContent & c) override; + void onPrimitive(uint32_t fid, const Content & c) override; public: AttributeInserter(search::AttributeVector & attribute, search::AttributeVector::DocId docId); @@ -103,7 +103,7 @@ private: PositionInserter(search::AttributeVector & attribute, search::AttributeVector::DocId docId); ~PositionInserter(); private: - void onPrimitive(uint32_t fid, const IteratorContent & c) override; + void onPrimitive(uint32_t fid, const Content & c) override; void onStructStart(const Content & fv) override; document::Field _fieldX; document::Field _fieldY; @@ -466,4 +466,3 @@ public: }; } - diff --git a/vdslib/src/vespa/vdslib/container/parameters.cpp b/vdslib/src/vespa/vdslib/container/parameters.cpp index d82f89da29d..c685a9b884f 100644 --- a/vdslib/src/vespa/vdslib/container/parameters.cpp +++ b/vdslib/src/vespa/vdslib/container/parameters.cpp @@ -4,6 +4,7 @@ #include <vespa/vespalib/objects/nbostream.h> #include <vespa/vespalib/objects/hexdump.h> #include <vespa/vespalib/stllike/hash_map.hpp> +#include <vespa/vespalib/util/xmlstream.h> using namespace vdslib; @@ -60,7 +61,7 @@ void Parameters::onDeserialize(const document::DocumentTypeRepo &repo, document: void Parameters::printXml(document::XmlOutputStream& xos) const { - using namespace document; + using namespace vespalib::xml; xos << XmlTag("parameters"); for (const auto & entry : _parameters) { xos << XmlTag("item") diff --git a/vsm/src/vespa/vsm/common/document.h b/vsm/src/vespa/vsm/common/document.h index a0341aaf7c0..ea0f9216ab9 100644 --- a/vsm/src/vespa/vsm/common/document.h +++ b/vsm/src/vespa/vsm/common/document.h @@ -4,6 +4,7 @@ #include <vespa/searchlib/query/base.h> #include <vespa/document/fieldvalue/fieldvalue.h> #include <vespa/vespalib/stllike/hash_map.h> +#include <map> namespace vespalib { class asciistream; diff --git a/vsm/src/vespa/vsm/searcher/fieldsearcher.h b/vsm/src/vespa/vsm/searcher/fieldsearcher.h index 3b82f68072b..e28275536f3 100644 --- a/vsm/src/vespa/vsm/searcher/fieldsearcher.h +++ b/vsm/src/vespa/vsm/searcher/fieldsearcher.h @@ -4,6 +4,7 @@ #include <vespa/searchlib/query/query.h> #include <vespa/vsm/common/document.h> #include <vespa/vsm/common/storagedocument.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> namespace vsm { @@ -79,9 +80,8 @@ public: size_t maxFieldLength() const { return _maxFieldLength; } private: - class IteratorHandler : public document::FieldValue::IteratorHandler { + class IteratorHandler : public document::fieldvalue::IteratorHandler { private: - typedef document::FieldValue::IteratorHandler::Content Content; FieldSearcher & _searcher; void onPrimitive(uint32_t fid, const Content & c) override; diff --git a/vsm/src/vespa/vsm/vsm/docsumfilter.cpp b/vsm/src/vespa/vsm/vsm/docsumfilter.cpp index 961add6d7d6..b7ed6c0b7da 100644 --- a/vsm/src/vespa/vsm/vsm/docsumfilter.cpp +++ b/vsm/src/vespa/vsm/vsm/docsumfilter.cpp @@ -4,6 +4,7 @@ #include "slimefieldwriter.h" #include <vespa/searchsummary/docsummary/summaryfieldconverter.h> #include <vespa/document/base/exceptions.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> #include <vespa/log/log.h> LOG_SETUP(".vsm.docsumfilter"); @@ -13,9 +14,8 @@ using namespace search::docsummary; namespace { -class Handler : public document::FieldValue::IteratorHandler { +class Handler : public document::fieldvalue::IteratorHandler { public: - typedef document::FieldValue::IteratorHandler::Content Content; }; struct IntResultHandler : public Handler { diff --git a/vsm/src/vespa/vsm/vsm/flattendocsumwriter.h b/vsm/src/vespa/vsm/vsm/flattendocsumwriter.h index 9c6ba8dae9c..aa58a6ae6df 100644 --- a/vsm/src/vespa/vsm/vsm/flattendocsumwriter.h +++ b/vsm/src/vespa/vsm/vsm/flattendocsumwriter.h @@ -2,6 +2,7 @@ #pragma once #include <vespa/document/fieldvalue/fieldvalue.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> #include <vespa/vsm/common/charbuffer.h> namespace vsm { @@ -10,10 +11,8 @@ namespace vsm { * This class is used to flatten out and write a complex field value. * A separator string is inserted between primitive field values. **/ -class FlattenDocsumWriter : public document::FieldValue::IteratorHandler { +class FlattenDocsumWriter : public document::fieldvalue::IteratorHandler { private: - typedef document::FieldValue::IteratorHandler::Content Content; - CharBuffer _output; vespalib::string _separator; bool _useSeparator; diff --git a/vsm/src/vespa/vsm/vsm/snippetmodifier.h b/vsm/src/vespa/vsm/vsm/snippetmodifier.h index 17d6bb44d4c..182f09d5d55 100644 --- a/vsm/src/vespa/vsm/vsm/snippetmodifier.h +++ b/vsm/src/vespa/vsm/vsm/snippetmodifier.h @@ -7,6 +7,7 @@ #include <vespa/vsm/common/fieldmodifier.h> #include <vespa/vsm/searcher/utf8substringsnippetmodifier.h> #include <vespa/document/fieldvalue/fieldvalue.h> +#include <vespa/document/fieldvalue/iteratorhandler.h> namespace vsm { @@ -19,11 +20,9 @@ namespace vsm { * responsible for modifying the field value by inserting unit separators before and after matches. * A group separator is inserted between primitive field values the same way as done by FlattenDocsumWriter. **/ -class SnippetModifier : public FieldModifier, public document::FieldValue::IteratorHandler +class SnippetModifier : public FieldModifier, public document::fieldvalue::IteratorHandler { private: - typedef document::FieldValue::IteratorHandler::Content Content; - UTF8SubstringSnippetModifier::SP _searcher; CharBuffer::SP _valueBuf; // buffer to store the final modified field value char _groupSep; |