// Copyright 2008 Google Inc.
// Author: Lincoln Smith
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef OPEN_VCDIFF_OUTPUT_STRING_H_
#define OPEN_VCDIFF_OUTPUT_STRING_H_

#include <stddef.h>  // size_t

namespace open_vcdiff {

// This interface allows clients of VCDiff[Streaming]Encoder and
// VCDiff[Streaming]Decoder to use different string types to receive the output
// of those interfaces.
//
// Only the following operations can be performed on an output string, and their
// semantics must be identical to the std::string methods of the same names:
//     append()
//     clear()
//     push_back()
//     size()
//
// The versions of these methods that take a std::string argument are not
// supported by OutputStringInterface.
//
// There is one additional operation that can be performed on an output string:
// ReserveAdditionalBytes().  This asks the underlying output type to reserve
// enough capacity for the number of additional bytes requested in addition to
// existing content.  The decoder knows the total expected output size in
// advance, so one large ReserveAdditionalBytes() operation precedes many small
// append() operations.  For output types that gain no advantage from knowing in
// advance how many bytes will be appended, ReserveAdditionalBytes() can be
// defined to do nothing.
class OutputStringInterface {
 public:
  virtual ~OutputStringInterface() { }

  virtual OutputStringInterface& append(const char* s, size_t n) = 0;

  virtual void clear() = 0;

  virtual void push_back(char c) = 0;

  virtual void ReserveAdditionalBytes(size_t res_arg) = 0;

  virtual size_t size() const = 0;
};

// This template can be used to wrap any class that supports the operations
// needed by OutputStringInterface, including std::string.  A class that has
// different names or syntax for these operations will need specialized
// definitions of OutputString methods -- see output_string_types.h for some
// examples of how to do this.
template<class StringClass>
class OutputString : public OutputStringInterface {
 public:
  explicit OutputString(StringClass* impl) : impl_(impl) { }

  virtual ~OutputString() { }

  virtual OutputString& append(const char* s, size_t n) {
    impl_->append(s, n);
    return *this;
  }

  virtual void clear() {
    impl_->clear();
  }

  virtual void push_back(char c) {
    impl_->push_back(c);
  }

  virtual void ReserveAdditionalBytes(size_t res_arg) {
    impl_->reserve(impl_->size() + res_arg);
  }

  virtual size_t size() const {
    return impl_->size();
  }

 protected:
  StringClass* impl_;

 private:
  // Making these private avoids implicit copy constructor & assignment operator
  OutputString(const OutputString&);
  void operator=(const OutputString&);
};

// Don't allow the OutputString template to be based upon a pointer to
// OutputStringInterface.  Enforce this restriction by defining this class to
// lack any functions expected of an OutputString.
template<> class OutputString<OutputStringInterface> { };

}  // namespace open_vcdiff

#endif  // OPEN_VCDIFF_OUTPUT_STRING_H_