//***************************************************************************
// This source code is copyrighted 2002 by Google Inc.  All rights
// reserved.  You are given a limited license to use this source code for
// purposes of participating in the Google programming contest.  If you
// choose to use or distribute the source code for any other purpose, you
// must either (1) first obtain written approval from Google, or (2)
// prominently display the foregoing copyright notice and the following
// warranty and liability disclaimer on each copy used or distributed.
// 
// The source code and repository (the "Software") is provided "AS IS",
// with no warranty, express or implied, including but not limited to the
// implied warranties of merchantability and fitness for a particular
// use.  In no event shall Google Inc. be liable for any damages, direct
// or indirect, even if advised of the possibility of such damages.
//***************************************************************************


#ifndef _NETUTIL_H
#define _NETUTIL_H

/*      Encoder                 -- For encoding data into byte stream
        Decoder                 -- For decoding data from byte stream
*/

#include <string.h>
#include <algorithm>        // for min
#include "goo-basictypes.h"
#include "goo-varint.h"

using namespace std;

/* Class for encoding data into a memory buffer */
class Encoder {
 public:
  // Empty constructor to create uninitialized encoder
  inline Encoder() { }

  // Initialize encoder to encode into "buf"
  explicit Encoder(void* buf, int maxn);
  void reset(void* buf, int maxn);

  // Encoding routines.  Note that these do not check bounds
  void put8(unsigned char v);
  void put16(uint16 v);
  void put32(uint32 v);
  void put64(uint64 v);
  void putn(const void* mem, int n);
  void putcn(const void* mem, int c, int n); // put no more than n byte,
                                             // stopping when c is put
  void puts(const void* mem);                // put a c-string including \0
  void putfloat(float f);
  void putdouble(double d);

  // Support for variable length encoding with 7 bits per byte
  // (these are just simple wrappers around the Varint module)
  static const int kVarintMax32 = Varint::kMax32;
  static const int kVarintMax64 = Varint::kMax64;

  void put_varint32(uint32 v);
  void put_varint64(uint64 v);
  void put_varsigned32(int32 v);        // Signed 32-bit encoding
  static int varint32_length(uint32 v); // Length of var encoding of "v"
  static int varint64_length(uint64 v); // Length of var encoding of "v"

  // Return number of bytes encoded so far
  int length() const;

 private:
  unsigned char* orig_;
  unsigned char* buf_;
  unsigned char* limit_;

  DISALLOW_EVIL_CONSTRUCTORS(Encoder);
};

/* Class for decoding data from a memory buffer */
class Decoder {
 public:
  // Empty constructor to create uninitialized decoder
  inline Decoder() { }

  // NOTE: for efficiency reasons, this is not virtual.  so don't add
  // any members that really need to be destructed, and be careful about
  // inheritance.
  ~Decoder() { }

  // Initialize decoder to decode from "buf"
  explicit Decoder(const void* buf, int maxn);
  void reset(const void* buf, int maxn);

  // Decoding routines.  Note that these do not check bounds
  unsigned char  get8();
  uint16 get16();
  uint32 get32();
  uint64 get64();
  float  getfloat();
  double getdouble();
  void   getn(void* mem, int n);
  void   getcn(void* mem, int c, int n);    // get no more than n bytes,
                                            // stopping after c is got
  void   gets(void* mem, int n);            // get a c-string no more than
                                            // n bytes. always appends '\0'
  void   skip(int n);
  unsigned char const* ptr();         // Return pointer to current position in buffer

  // "get_varint" actually checks bounds
  bool get_varint32(uint32* v);
  bool get_varint64(uint64* v);
  bool get_varsigned32(int32* v);

  int pos() const;
  // Return number of bytes decoded so far

  int avail() const;
  // Return number of available bytes to read
 private:
  const unsigned char* orig_;
  const unsigned char* buf_;
  const unsigned char* limit_;
};

/***** Implementation details.  Clients should ignore them. *****/

inline Encoder::Encoder(void* b, int maxn) {
  orig_ = buf_ = reinterpret_cast<unsigned char*>(b);
  limit_ = orig_ + maxn;
}

inline void Encoder::reset(void* b, int maxn) {
  orig_ = buf_ = reinterpret_cast<unsigned char*>(b);
  limit_ = orig_ + maxn;
}

inline int Encoder::length() const {
  return (buf_ - orig_);
}

inline void Encoder::putn(const void* src, int n) {
  memcpy(buf_, src, n);
  buf_ += n;
}

inline void Encoder::putcn(const void* src, int c, int n) {
  unsigned char *old = buf_;
  buf_ = static_cast<unsigned char *>(memccpy(buf_, src, c, n));
  if (buf_ == NULL)
    buf_ = old + n;
}

inline void Encoder::puts(const void* src) {
  putcn(src, '\0', limit_ - buf_);
}

inline void Encoder::put_varint32(uint32 v) {
  buf_ = reinterpret_cast<unsigned char*>
         (Varint::Encode32(reinterpret_cast<char*>(buf_), v));
}

inline void Encoder::put_varint64(uint64 v) {
  buf_ = reinterpret_cast<unsigned char*>
         (Varint::Encode64(reinterpret_cast<char*>(buf_), v));
}

inline void Encoder::put_varsigned32(int32 n) {
  // Encode sign in low-bit
  int sign = (n < 0) ? 1 : 0;
  uint32 mag = (n < 0) ? -n : n;
  put_varint32((mag << 1) | sign);
}

inline Decoder::Decoder(const void* b, int maxn) {
  orig_ = buf_ = reinterpret_cast<const unsigned char*>(b);
  limit_ = orig_ + maxn;
}

inline void Decoder::reset(const void* b, int maxn) {
  orig_ = buf_ = reinterpret_cast<const unsigned char*>(b);
  limit_ = orig_ + maxn;
}

inline int Decoder::pos() const {
  return (buf_ - orig_);
}

inline int Decoder::avail() const {
  return (limit_ - buf_);
}

inline void Decoder::getn(void* dst, int n) {
  memcpy(dst, buf_, n);
  buf_ += n;
}

inline void Decoder::getcn(void* dst, int c, int n) {
  void *ptr;
  ptr = memccpy(dst, buf_, c, n);
  if (ptr == NULL)
    buf_ = buf_ + n;
  else
    buf_ = buf_ + (reinterpret_cast<typeof(buf_)>(ptr) -
                   reinterpret_cast<typeof(buf_)>(dst));
}

inline void Decoder::gets(void* dst, int n) {
  int len = min((n - 1), (limit_ - buf_));
  (reinterpret_cast<char *>(dst))[len] = '\0';
  getcn(dst, '\0', len);
}

inline void Decoder::skip(int n) {
  buf_ += n;
}

inline unsigned char const* Decoder::ptr() {
  return buf_;
}

inline bool Decoder::get_varsigned32(int32* v) {
  uint32 coding;
  if (get_varint32(&coding)) {
    int sign = coding & 1;
    int32 mag = coding >> 1;
    *v = sign ? -mag : mag;
    return true;
  } else {
    return false;
  }
}


#ifdef __i386__ /* __i386__ */

/* On i386, misaligned operations are no slower than decomposed
   byte-wise operations, and the host data is little-endian, so we
   have particularly efficient implementations. */

inline void Encoder::put8(unsigned char v) {
  *buf_ = v;
  buf_ += sizeof(v);
}

inline void Encoder::put16(uint16 v) {
  *(reinterpret_cast<uint16*>(buf_)) = v;
  buf_ += sizeof(v);
}

inline void Encoder::put32(uint32 v) {
  *(reinterpret_cast<uint32*>(buf_)) = v;
  buf_ += sizeof(v);
}

inline void Encoder::put64(uint64 v) {
  *(reinterpret_cast<uint64*>(buf_)) = v;
  buf_ += sizeof(v);
}

inline void Encoder::putfloat(float f) {
  *(reinterpret_cast<float*>(buf_)) = f;
  buf_ += sizeof(f);
}

inline void Encoder::putdouble(double d) {
  *(reinterpret_cast<float*>(buf_)) = d;
  buf_ += sizeof(d);
}



inline unsigned char Decoder::get8() {
  const unsigned char v = *buf_;
  buf_ += sizeof(v);
  return v;
}

inline uint16 Decoder::get16() {
  const uint16 v = *(reinterpret_cast<const uint16*>(buf_));
  buf_ += sizeof(v);
  return v;
}

inline uint32 Decoder::get32() {
  const uint32 v = *(reinterpret_cast<const uint32*>(buf_));
  buf_ += sizeof(v);
  return v;
}

inline uint64 Decoder::get64() {
  const uint64 v = *(reinterpret_cast<const uint64*>(buf_));
  buf_ += sizeof(v);
  return v;
}


#else

inline void Encoder::put8(unsigned char v) {
  *buf_ = v;
  buf_ += sizeof(v);
}

inline void Encoder::put16(uint16 v) {
  *buf_++ = (unsigned char)v;
  *buf_++ = (unsigned char)(v >> 8);
}

inline void Encoder::put32(uint32 v) {
  *buf_++ = (unsigned char)v;
  *buf_++ = (unsigned char)(v >> 8);
  *buf_++ = (unsigned char)(v >> 16);
  *buf_++ = (unsigned char)(v >> 24);
}

inline void Encoder::put64(uint64 v) {
  *buf_++ = (unsigned char)v;
  *buf_++ = (unsigned char)(v >> 8);
  *buf_++ = (unsigned char)(v >> 16);
  *buf_++ = (unsigned char)(v >> 24);
  *buf_++ = (unsigned char)(v >> 32);
  *buf_++ = (unsigned char)(v >> 40);
  *buf_++ = (unsigned char)(v >> 48);
  *buf_++ = (unsigned char)(v >> 56);
}


inline void Encoder::putfloat(float f) {
  assert(sizeof(f) == 4);
  *buf_++ = *(((unsigned char*)(&f)) + 0);
  *buf_++ = *(((unsigned char*)(&f)) + 1);
  *buf_++ = *(((unsigned char*)(&f)) + 2);
  *buf_++ = *(((unsigned char*)(&f)) + 3);
}

inline void Encoder::putdouble(double d) {
  assert(sizeof(d) == 8);
  *buf_++ = *(((unsigned char*)(&d)) + 0);
  *buf_++ = *(((unsigned char*)(&d)) + 1);
  *buf_++ = *(((unsigned char*)(&d)) + 2);
  *buf_++ = *(((unsigned char*)(&d)) + 3);
  *buf_++ = *(((unsigned char*)(&d)) + 4);
  *buf_++ = *(((unsigned char*)(&d)) + 5);
  *buf_++ = *(((unsigned char*)(&d)) + 6);
  *buf_++ = *(((unsigned char*)(&d)) + 7);
}

inline unsigned char Decoder::get8() {
  const unsigned char v = *buf_;
  buf_ += sizeof(v);
  return v;
}

inline uint16 Decoder::get16() {
  const uint16 v = buf_[0] + ((uint16)buf_[1] << 8);
  buf_ += sizeof(v);
  return v;
}

inline uint32 Decoder::get32() {
  const uint32 v = buf_[0]                 + ((uint32)buf_[1] << 8) +
                   ((uint32)buf_[2] << 16) + ((uint32)buf_[3] << 24);
  buf_ += sizeof(v);
  return v;
}

inline uint64 Decoder::get64() {
  const uint64 v =  buf_[0]                 + ((uint64)buf_[1] << 8) +
                    ((uint64)buf_[2] << 16) + ((uint64)buf_[3] << 24) +
                    ((uint64)buf_[4] << 32) + ((uint64)buf_[5] << 40) +
                    ((uint64)buf_[6] << 48) + ((uint64)buf_[7] << 56);
  buf_ += sizeof(v);
  return v;
}


#endif /* __i386__ */

inline float Decoder::getfloat() {
  float v;
  memcpy(&v, buf_, sizeof(v));
  buf_ += sizeof(v);
  return v;
}

inline double Decoder::getdouble() {
  double v;
  memcpy(&v, buf_, sizeof(v));
  buf_ += sizeof(v);
  return v;
}

#endif /* _NETUTIL_H */

