wdang
9/21/2018 - 2:03 AM

utility.h

// Copyright 2018 William Dang (william.dang@utah.edu).
//
// 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.
#pragma once

#include <fstream>
#include <string>
#include <vector>
#include <unordered_map>
// utilty.h contains general string and file utility functions

// Returns the length of the given array.
// compile time assertion with "ERROR_Non_Array_Type"
// if x is not a static array.
#define ARRAY_COUNT(x) (sizeof(::internal::ERROR_Non_Array_Type(x)))

// Replace(source,substring,replacement): In place string search and replace
//
// @source: pointer to a string used for the search
// @substring: string to search for in source
// @replacement: string to replace substring with in source
//
// Returns the number of substrings replaced
inline size_t Replace(std::string* source,
       const std::string& substring, const std::string& replacement) {
  size_t pos = 0;
  while ((pos = source->find(substring, pos)) != std::string::npos) {
    source->replace(pos, substring.length(), replacement);
    pos += replacement.length();
  }
  return replacement.length() ? pos/replacement.length(): 0;
}

// Replace(source,substring,replacement): In place string search and replace.
//
// @source: string used for the search
// @substring: the string to search for in source
// @replacement: the string to replace substring with in source
//
// Returns a copy of source with each substring replaced with the given
// replacement string
inline std::string Replace(const std::string& source,
       const std::string& substring, const std::string& replacement) {
  std::string rv(source);
  Replace(&rv,substring,replacement);
  return rv;
}


// ToUnixPaths(source): Returns a copy of source with all backslashes
// replaced with forward slashes does not verify that source is an 
// actual path string
inline std::string ToUnixPaths(const std::string& source) {
  return Replace(source,"\\","/");
}

// StripCurrentDirReference(path): Removes leading ./ and .\ from the given path
inline std::string StripCurrentDirReference(const std::string& path) {
  if(path.size() && path[0] == '.') {
     if(path[1] == '/' || path[1] == '\\')
       return path.substr(2);
  }
  return path;
}


// FileToString(path,str): Open the file in 'path' and read the contents into
// the given string.
//
// @path: path to a file
// @str: buffer to hold the contents of 'path'
//
// Returns true on success
inline bool FileToString(const std::string& path, std::string* str) {
  if(!str) return false;

  std::ifstream fs(path.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
  const std::streamsize size = fs.tellg();

  if(size == -1) return false;

  str->reserve(static_cast<size_t>(size));
  for(int i = 0; i < size; ++i) {
    str->push_back('\0');
  }

  if(!fs.is_open()){
    // doesn't hurt to try again, io is magical sometimes
    fs.open(path.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
    if(!fs.is_open()){
      return false;
    }
  }

  fs.seekg(0, std::ios::beg);
  fs.read(&(*str)[0], size);
  fs.close();

  return true;
}

// FileToString(path,str): Fast unchecked file to string function.
//
// @path: path to a file
//
// Returns the contents of the file located at path
inline std::string FileToString(const std::string& path){
  return std::string(static_cast<const std::ostringstream&>(std::ostringstream() << std::ifstream(path.c_str()).rdbuf()).str());
}

// AbsoluteFilePath(path) Returns a copy of the given path
// string as an absolute file path
std::string AbsoluteFilePath(const std::string& path);

namespace internal {
// ARRAY_COUNT implementation
#if defined(_WIN64) || defined(__LP64__) || defined(_M_AMD64)
template<class ArrayType, size_t N>
char(__unaligned &ERROR_Non_Array_Type(ArrayType(&)[N]))[N];
#endif

// GCC wants both const and non-const versions
#ifndef _MSC_VER
template<class ArrayType, size_t N>
char(&ERROR_Non_Array_Type(const ArrayType(&)[N]))[N];
#endif

template<class ArrayType, size_t N>
char(&ERROR_Non_Array_Type(ArrayType(&)[N]))[N];
}