// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
#define GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__

#include <google/protobuf/map_field.h>
#include <google/protobuf/reflection.h>
#include <google/protobuf/repeated_field.h>

namespace google {
namespace protobuf {
namespace internal {
// A base class for RepeatedFieldAccessor implementations that can support
// random-access efficiently. All iterator methods delegates the work to
// corresponding random-access methods.
class RandomAccessRepeatedFieldAccessor : public RepeatedFieldAccessor {
 public:
  Iterator* BeginIterator(const Field* /*data*/) const override {
    return PositionToIterator(0);
  }
  Iterator* EndIterator(const Field* data) const override {
    return PositionToIterator(this->Size(data));
  }
  Iterator* CopyIterator(const Field* /*data*/,
                         const Iterator* iterator) const override {
    return const_cast<Iterator*>(iterator);
  }
  Iterator* AdvanceIterator(const Field* /*data*/,
                            Iterator* iterator) const override {
    return PositionToIterator(IteratorToPosition(iterator) + 1);
  }
  bool EqualsIterator(const Field* /*data*/, const Iterator* a,
                      const Iterator* b) const override {
    return a == b;
  }
  void DeleteIterator(const Field* /*data*/,
                      Iterator* /*iterator*/) const override {}
  const Value* GetIteratorValue(const Field* data, const Iterator* iterator,
                                Value* scratch_space) const override {
    return Get(data, static_cast<int>(IteratorToPosition(iterator)),
               scratch_space);
  }

 protected:
  ~RandomAccessRepeatedFieldAccessor() = default;

 private:
  static intptr_t IteratorToPosition(const Iterator* iterator) {
    return reinterpret_cast<intptr_t>(iterator);
  }
  static Iterator* PositionToIterator(intptr_t position) {
    return reinterpret_cast<Iterator*>(position);
  }
};

// Base class for RepeatedFieldAccessor implementations that manipulates
// RepeatedField<T>.
template <typename T>
class RepeatedFieldWrapper : public RandomAccessRepeatedFieldAccessor {
 public:
  RepeatedFieldWrapper() {}
  bool IsEmpty(const Field* data) const override {
    return GetRepeatedField(data)->empty();
  }
  int Size(const Field* data) const override {
    return GetRepeatedField(data)->size();
  }
  const Value* Get(const Field* data, int index,
                   Value* scratch_space) const override {
    return ConvertFromT(GetRepeatedField(data)->Get(index), scratch_space);
  }
  void Clear(Field* data) const override {
    MutableRepeatedField(data)->Clear();
  }
  void Set(Field* data, int index, const Value* value) const override {
    MutableRepeatedField(data)->Set(index, ConvertToT(value));
  }
  void Add(Field* data, const Value* value) const override {
    MutableRepeatedField(data)->Add(ConvertToT(value));
  }
  void RemoveLast(Field* data) const override {
    MutableRepeatedField(data)->RemoveLast();
  }
  void SwapElements(Field* data, int index1, int index2) const override {
    MutableRepeatedField(data)->SwapElements(index1, index2);
  }

 protected:
  ~RepeatedFieldWrapper() = default;
  typedef RepeatedField<T> RepeatedFieldType;
  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
    return reinterpret_cast<const RepeatedFieldType*>(data);
  }
  static RepeatedFieldType* MutableRepeatedField(Field* data) {
    return reinterpret_cast<RepeatedFieldType*>(data);
  }

  // Convert an object received by this accessor to an object to be stored in
  // the underlying RepeatedField.
  virtual T ConvertToT(const Value* value) const = 0;

  // Convert an object stored in RepeatedPtrField to an object that will be
  // returned by this accessor. If the two objects have the same type (true for
  // string fields with ctype=STRING), a pointer to the source object can be
  // returned directly. Otherwise, data should be copied from value to
  // scratch_space and scratch_space should be returned.
  virtual const Value* ConvertFromT(const T& value,
                                    Value* scratch_space) const = 0;
};

// Base class for RepeatedFieldAccessor implementations that manipulates
// RepeatedPtrField<T>.
template <typename T>
class RepeatedPtrFieldWrapper : public RandomAccessRepeatedFieldAccessor {
 public:
  bool IsEmpty(const Field* data) const override {
    return GetRepeatedField(data)->empty();
  }
  int Size(const Field* data) const override {
    return GetRepeatedField(data)->size();
  }
  const Value* Get(const Field* data, int index,
                   Value* scratch_space) const override {
    return ConvertFromT(GetRepeatedField(data)->Get(index), scratch_space);
  }
  void Clear(Field* data) const override {
    MutableRepeatedField(data)->Clear();
  }
  void Set(Field* data, int index, const Value* value) const override {
    ConvertToT(value, MutableRepeatedField(data)->Mutable(index));
  }
  void Add(Field* data, const Value* value) const override {
    T* allocated = New(value);
    ConvertToT(value, allocated);
    MutableRepeatedField(data)->AddAllocated(allocated);
  }
  void RemoveLast(Field* data) const override {
    MutableRepeatedField(data)->RemoveLast();
  }
  void SwapElements(Field* data, int index1, int index2) const override {
    MutableRepeatedField(data)->SwapElements(index1, index2);
  }

 protected:
  ~RepeatedPtrFieldWrapper() = default;
  typedef RepeatedPtrField<T> RepeatedFieldType;
  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
    return reinterpret_cast<const RepeatedFieldType*>(data);
  }
  static RepeatedFieldType* MutableRepeatedField(Field* data) {
    return reinterpret_cast<RepeatedFieldType*>(data);
  }

  // Create a new T instance. For repeated message fields, T can be specified
  // as google::protobuf::Message so we can't use "new T()" directly. In that case, value
  // should be a message of the same type (it's ensured by the caller) and a
  // new message object will be created using it.
  virtual T* New(const Value* value) const = 0;

  // Convert an object received by this accessor to an object that will be
  // stored in the underlying RepeatedPtrField.
  virtual void ConvertToT(const Value* value, T* result) const = 0;

  // Convert an object stored in RepeatedPtrField to an object that will be
  // returned by this accessor. If the two objects have the same type (true for
  // string fields with ctype=STRING), a pointer to the source object can be
  // returned directly. Otherwise, data should be copied from value to
  // scratch_space and scratch_space should be returned.
  virtual const Value* ConvertFromT(const T& value,
                                    Value* scratch_space) const = 0;
};

// An implementation of RandomAccessRepeatedFieldAccessor that manipulates
// MapFieldBase.
class MapFieldAccessor final : public RandomAccessRepeatedFieldAccessor {
 public:
  MapFieldAccessor() {}
  virtual ~MapFieldAccessor() {}
  bool IsEmpty(const Field* data) const override {
    return GetRepeatedField(data)->empty();
  }
  int Size(const Field* data) const override {
    return GetRepeatedField(data)->size();
  }
  const Value* Get(const Field* data, int index,
                   Value* scratch_space) const override {
    return ConvertFromEntry(GetRepeatedField(data)->Get(index), scratch_space);
  }
  void Clear(Field* data) const override {
    MutableRepeatedField(data)->Clear();
  }
  void Set(Field* data, int index, const Value* value) const override {
    ConvertToEntry(value, MutableRepeatedField(data)->Mutable(index));
  }
  void Add(Field* data, const Value* value) const override {
    Message* allocated = New(value);
    ConvertToEntry(value, allocated);
    MutableRepeatedField(data)->AddAllocated(allocated);
  }
  void RemoveLast(Field* data) const override {
    MutableRepeatedField(data)->RemoveLast();
  }
  void SwapElements(Field* data, int index1, int index2) const override {
    MutableRepeatedField(data)->SwapElements(index1, index2);
  }
  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
            Field* other_data) const override {
    GOOGLE_CHECK(this == other_mutator);
    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
  }

 protected:
  typedef RepeatedPtrField<Message> RepeatedFieldType;
  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
    return reinterpret_cast<const RepeatedFieldType*>(
        (&reinterpret_cast<const MapFieldBase*>(data)->GetRepeatedField()));
  }
  static RepeatedFieldType* MutableRepeatedField(Field* data) {
    return reinterpret_cast<RepeatedFieldType*>(
        reinterpret_cast<MapFieldBase*>(data)->MutableRepeatedField());
  }
  virtual Message* New(const Value* value) const {
    return static_cast<const Message*>(value)->New();
  }
  // Convert an object received by this accessor to an MapEntry message to be
  // stored in the underlying MapFieldBase.
  virtual void ConvertToEntry(const Value* value, Message* result) const {
    result->CopyFrom(*static_cast<const Message*>(value));
  }
  // Convert a MapEntry message stored in the underlying MapFieldBase to an
  // object that will be returned by this accessor.
  virtual const Value* ConvertFromEntry(const Message& value,
                                        Value* /*scratch_space*/) const {
    return static_cast<const Value*>(&value);
  }
};

// Default implementations of RepeatedFieldAccessor for primitive types.
template <typename T>
class RepeatedFieldPrimitiveAccessor final : public RepeatedFieldWrapper<T> {
  typedef void Field;
  typedef void Value;
  using RepeatedFieldWrapper<T>::MutableRepeatedField;

 public:
  RepeatedFieldPrimitiveAccessor() {}
  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
            Field* other_data) const override {
    // Currently RepeatedFieldPrimitiveAccessor is the only implementation of
    // RepeatedFieldAccessor for primitive types. As we are using singletons
    // for these accessors, here "other_mutator" must be "this".
    GOOGLE_CHECK(this == other_mutator);
    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
  }

 protected:
  T ConvertToT(const Value* value) const override {
    return *static_cast<const T*>(value);
  }
  const Value* ConvertFromT(const T& value,
                            Value* /*scratch_space*/) const override {
    return static_cast<const Value*>(&value);
  }
};

// Default implementation of RepeatedFieldAccessor for string fields with
// ctype=STRING.
class RepeatedPtrFieldStringAccessor final
    : public RepeatedPtrFieldWrapper<std::string> {
  typedef void Field;
  typedef void Value;
  using RepeatedFieldAccessor::Add;

 public:
  RepeatedPtrFieldStringAccessor() {}
  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
            Field* other_data) const override {
    if (this == other_mutator) {
      MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
    } else {
      RepeatedPtrField<std::string> tmp;
      tmp.Swap(MutableRepeatedField(data));
      int other_size = other_mutator->Size(other_data);
      for (int i = 0; i < other_size; ++i) {
        Add<std::string>(data, other_mutator->Get<std::string>(other_data, i));
      }
      int size = Size(data);
      other_mutator->Clear(other_data);
      for (int i = 0; i < size; ++i) {
        other_mutator->Add<std::string>(other_data, tmp.Get(i));
      }
    }
  }

 protected:
  std::string* New(const Value*) const override { return new std::string(); }
  void ConvertToT(const Value* value, std::string* result) const override {
    *result = *static_cast<const std::string*>(value);
  }
  const Value* ConvertFromT(const std::string& value,
                            Value* /*scratch_space*/) const override {
    return static_cast<const Value*>(&value);
  }
};


class RepeatedPtrFieldMessageAccessor final
    : public RepeatedPtrFieldWrapper<Message> {
  typedef void Field;
  typedef void Value;

 public:
  RepeatedPtrFieldMessageAccessor() {}
  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
            Field* other_data) const override {
    GOOGLE_CHECK(this == other_mutator);
    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
  }

 protected:
  Message* New(const Value* value) const override {
    return static_cast<const Message*>(value)->New();
  }
  void ConvertToT(const Value* value, Message* result) const override {
    result->CopyFrom(*static_cast<const Message*>(value));
  }
  const Value* ConvertFromT(const Message& value,
                            Value* /*scratch_space*/) const override {
    return static_cast<const Value*>(&value);
  }
};
}  // namespace internal
}  // namespace protobuf
}  // namespace google

#endif  // GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
