// compat.h
//
// 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.
//
// Author: riley@google.com (Michael Riley)
//
// \file
// Google compatibility declarations and inline definitions.

#ifndef FST_LIB_COMPAT_H__
#define FST_LIB_COMPAT_H__

#include <dlfcn.h>

#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>

// Makes copy constructor and operator= private
#define DISALLOW_COPY_AND_ASSIGN(type)    \
  type(const type&);                      \
  void operator=(const type&)

#include <fst/config.h>
#include <fst/types.h>
#include <fst/lock.h>
#include <fst/flags.h>
#include <fst/log.h>

#ifdef HAVE_ICU
#include <fst/icu.h>
#endif

using std::cin;
using std::cout;
using std::cerr;
using std::endl;
using std::string;

void FailedNewHandler();

namespace fst {

using namespace std;

void SplitToVector(char *line, const char *delim,
                   std::vector<char *> *vec, bool omit_empty_strings);

// Downcasting
template<typename To, typename From>
inline To down_cast(From* f) {
  return static_cast<To>(f);
}

// Bitcasting
template <class Dest, class Source>
inline Dest bit_cast(const Source& source) {
  // Compile time assertion: sizeof(Dest) == sizeof(Source)
  // A compile error here means your Dest and Source have different sizes.
  typedef char VerifySizesAreEqual [sizeof(Dest) == sizeof(Source) ? 1 :
                                    -1];
  Dest dest;
  memcpy(&dest, &source, sizeof(dest));
  return dest;
}

// Check sums
class CheckSummer {
 public:
  CheckSummer() : count_(0) {
    check_sum_.resize(kCheckSumLength, '\0');
  }

  void Reset() {
    count_ = 0;
    for (int i = 0; i < kCheckSumLength; ++i)
      check_sum_[0] = '\0';
  }

  void Update(void const *data, int size) {
    const char *p = reinterpret_cast<const char *>(data);
    for (int i = 0; i < size; ++i)
      check_sum_[(count_++) % kCheckSumLength] ^= p[i];
  }

  void Update(string const &data) {
    for (int i = 0; i < data.size(); ++i)
      check_sum_[(count_++) % kCheckSumLength] ^= data[i];
  }

  string Digest() {
    return check_sum_;
  }

 private:
  static const int kCheckSumLength = 32;
  int count_;
  string check_sum_;

  DISALLOW_COPY_AND_ASSIGN(CheckSummer);
};

// Define the UTF8 string conversion function to throw an error
// when the ICU Library is missing or disabled.
#ifndef HAVE_ICU

template <class Label>
bool UTF8StringToLabels(const string&, std::vector<Label>*) {
  LOG(ERROR) << "UTF8StringToLabels: ICU Library required for UTF8 handling";
  return false;
}

template <class Label>
bool LabelsToUTF8String(const std::vector<Label>&, string*) {
  LOG(ERROR) << "LabelsToUTF8String: ICU Library required for UTF8 handling";
  return false;
}

#endif  // HAVE_ICU

}  // namespace fst


// Define missing hash functions if needed
/*#ifndef HAVE_STD__TR1__HASH_LONG_LONG_UNSIGNED_
namespace std {
namespace tr1 {

template <class T> class hash;

template<> struct hash<uint64> {
  size_t operator()(uint64 x) const { return x; }
};

}
}
#endif  // HAVE_STD__TR1__HASH_LONG_LONG_UNSIGNED_ */

#endif  // FST_LIB_COMPAT_H__
