text: // Copyright 2014 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef V8_UNICODE_DECODER_H_
  #define V8_UNICODE_DECODER_H_
  
  #include <sys/types.h>
  #include "src/globals.h"
  #include "src/utils.h"
  
  namespace unibrow {
  
  class V8_EXPORT_PRIVATE Utf8DecoderBase {
   public:
    // Initialization done in subclass.
    inline Utf8DecoderBase();
    inline Utf8DecoderBase(uint16_t* buffer, size_t buffer_length,
                           const uint8_t* stream, size_t stream_length);
    inline size_t Utf16Length() const { return utf16_length_; }
  
   protected:
    // This reads all characters and sets the utf16_length_.
    // The first buffer_length utf16 chars are cached in the buffer.
    void Reset(uint16_t* buffer, size_t buffer_length, const uint8_t* stream,
               size_t stream_length);
    static void WriteUtf16Slow(const uint8_t* stream, size_t stream_length,
                               uint16_t* data, size_t length);
    const uint8_t* unbuffered_start_;
    size_t unbuffered_length_;
    size_t utf16_length_;
    bool last_byte_of_buffer_unused_;
  
   private:
    DISALLOW_COPY_AND_ASSIGN(Utf8DecoderBase);
  };
  
  template <size_t kBufferSize>
  class Utf8Decoder : public Utf8DecoderBase {
   public:
    inline Utf8Decoder() {}
    inline Utf8Decoder(const char* stream, size_t length);
    inline void Reset(const char* stream, size_t length);
    inline size_t WriteUtf16(uint16_t* data, size_t length) const;
  
   private:
    uint16_t buffer_[kBufferSize];
  };
  
  
  Utf8DecoderBase::Utf8DecoderBase()
      : unbuffered_start_(NULL),
        unbuffered_length_(0),
        utf16_length_(0),
        last_byte_of_buffer_unused_(false) {}
  
  
  Utf8DecoderBase::Utf8DecoderBase(uint16_t* buffer, size_t buffer_length,
                                   const uint8_t* stream, size_t stream_length) {
    Reset(buffer, buffer_length, stream, stream_length);
  }
  
  
  template <size_t kBufferSize>
  Utf8Decoder<kBufferSize>::Utf8Decoder(const char* stream, size_t length)
      : Utf8DecoderBase(buffer_, kBufferSize,
                        reinterpret_cast<const uint8_t*>(stream), length) {}
  
  
  template <size_t kBufferSize>
  void Utf8Decoder<kBufferSize>::Reset(const char* stream, size_t length) {
    Utf8DecoderBase::Reset(buffer_, kBufferSize,
                           reinterpret_cast<const uint8_t*>(stream), length);
  }
  
  
  template <size_t kBufferSize>
  size_t Utf8Decoder<kBufferSize>::WriteUtf16(uint16_t* data,
                                              size_t length) const {
    DCHECK(length > 0);
    if (length > utf16_length_) length = utf16_length_;
    // memcpy everything in buffer.
    size_t buffer_length =
        last_byte_of_buffer_unused_ ? kBufferSize - 1 : kBufferSize;
    size_t memcpy_length = length <= buffer_length ? length : buffer_length;
    v8::internal::MemCopy(data, buffer_, memcpy_length * sizeof(uint16_t));
    if (length <= buffer_length) return length;
    DCHECK(unbuffered_start_ != NULL);
    // Copy the rest the slow way.
    WriteUtf16Slow(unbuffered_start_, unbuffered_length_, data + buffer_length,
                   length - buffer_length);
    return length;
  }
  
  class Latin1 {
   public:
    static const unsigned kMaxChar = 0xff;
    // Returns 0 if character does not convert to single latin-1 character
    // or if the character doesn't not convert back to latin-1 via inverse
    // operation (upper to lower, etc).
    static inline uint16_t ConvertNonLatin1ToLatin1(uint16_t);
  };
  
  
  uint16_t Latin1::ConvertNonLatin1ToLatin1(uint16_t c) {
    DCHECK(c > Latin1::kMaxChar);
    switch (c) {
      // This are equivalent characters in unicode.
      case 0x39c:
      case 0x3bc:
        return 0xb5;
      // This is an uppercase of a Latin-1 character
      // outside of Latin-1.
      case 0x178:
        return 0xff;
    }
    return 0;
  }
  
  
  }  // namespace unibrow
  
  #endif  // V8_UNICODE_DECODER_H_
  