Chris@49: // Copyright (C) 2008-2012 NICTA (www.nicta.com.au) Chris@49: // Copyright (C) 2008-2012 Conrad Sanderson Chris@49: // Copyright (C) 2009-2010 Ian Cullinan Chris@49: // Copyright (C) 2012 Ryan Curtin Chris@49: // Copyright (C) 2013 Szabolcs Horvat Chris@49: // Chris@49: // This Source Code Form is subject to the terms of the Mozilla Public Chris@49: // License, v. 2.0. If a copy of the MPL was not distributed with this Chris@49: // file, You can obtain one at http://mozilla.org/MPL/2.0/. Chris@49: Chris@49: Chris@49: //! \addtogroup diskio Chris@49: //! @{ Chris@49: Chris@49: Chris@49: //! Generate the first line of the header used for saving matrices in text format. Chris@49: //! Format: "ARMA_MAT_TXT_ABXYZ". Chris@49: //! A is one of: I (for integral types) or F (for floating point types). Chris@49: //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types). Chris@49: //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes. Chris@49: template Chris@49: inline Chris@49: std::string Chris@49: diskio::gen_txt_header(const Mat& x) Chris@49: { Chris@49: arma_type_check(( is_supported_elem_type::value == false )); Chris@49: Chris@49: arma_ignore(x); Chris@49: Chris@49: if(is_u8::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IU001"); Chris@49: } Chris@49: else Chris@49: if(is_s8::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IS001"); Chris@49: } Chris@49: else Chris@49: if(is_u16::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IU002"); Chris@49: } Chris@49: else Chris@49: if(is_s16::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IS002"); Chris@49: } Chris@49: else Chris@49: if(is_u32::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IU004"); Chris@49: } Chris@49: else Chris@49: if(is_s32::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IS004"); Chris@49: } Chris@49: #if defined(ARMA_USE_U64S64) Chris@49: else Chris@49: if(is_u64::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IU008"); Chris@49: } Chris@49: else Chris@49: if(is_s64::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IS008"); Chris@49: } Chris@49: #endif Chris@49: #if defined(ARMA_ALLOW_LONG) Chris@49: else Chris@49: if(is_ulng_t_32::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IU004"); Chris@49: } Chris@49: else Chris@49: if(is_slng_t_32::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IS004"); Chris@49: } Chris@49: else Chris@49: if(is_ulng_t_64::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IU008"); Chris@49: } Chris@49: else Chris@49: if(is_slng_t_64::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_IS008"); Chris@49: } Chris@49: #endif Chris@49: else Chris@49: if(is_float::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_FN004"); Chris@49: } Chris@49: else Chris@49: if(is_double::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_FN008"); Chris@49: } Chris@49: else Chris@49: if(is_complex_float::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_FC008"); Chris@49: } Chris@49: else Chris@49: if(is_complex_double::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_TXT_FC016"); Chris@49: } Chris@49: else Chris@49: { Chris@49: return std::string(); Chris@49: } Chris@49: Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Generate the first line of the header used for saving matrices in binary format. Chris@49: //! Format: "ARMA_MAT_BIN_ABXYZ". Chris@49: //! A is one of: I (for integral types) or F (for floating point types). Chris@49: //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types). Chris@49: //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes. Chris@49: template Chris@49: inline Chris@49: std::string Chris@49: diskio::gen_bin_header(const Mat& x) Chris@49: { Chris@49: arma_type_check(( is_supported_elem_type::value == false )); Chris@49: Chris@49: arma_ignore(x); Chris@49: Chris@49: if(is_u8::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IU001"); Chris@49: } Chris@49: else Chris@49: if(is_s8::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IS001"); Chris@49: } Chris@49: else Chris@49: if(is_u16::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IU002"); Chris@49: } Chris@49: else Chris@49: if(is_s16::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IS002"); Chris@49: } Chris@49: else Chris@49: if(is_u32::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IU004"); Chris@49: } Chris@49: else Chris@49: if(is_s32::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IS004"); Chris@49: } Chris@49: #if defined(ARMA_USE_U64S64) Chris@49: else Chris@49: if(is_u64::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IU008"); Chris@49: } Chris@49: else Chris@49: if(is_s64::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IS008"); Chris@49: } Chris@49: #endif Chris@49: #if defined(ARMA_ALLOW_LONG) Chris@49: else Chris@49: if(is_ulng_t_32::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IU004"); Chris@49: } Chris@49: else Chris@49: if(is_slng_t_32::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IS004"); Chris@49: } Chris@49: else Chris@49: if(is_ulng_t_64::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IU008"); Chris@49: } Chris@49: else Chris@49: if(is_slng_t_64::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_IS008"); Chris@49: } Chris@49: #endif Chris@49: else Chris@49: if(is_float::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_FN004"); Chris@49: } Chris@49: else Chris@49: if(is_double::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_FN008"); Chris@49: } Chris@49: else Chris@49: if(is_complex_float::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_FC008"); Chris@49: } Chris@49: else Chris@49: if(is_complex_double::value == true) Chris@49: { Chris@49: return std::string("ARMA_MAT_BIN_FC016"); Chris@49: } Chris@49: else Chris@49: { Chris@49: return std::string(); Chris@49: } Chris@49: Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Generate the first line of the header used for saving matrices in binary format. Chris@49: //! Format: "ARMA_SPM_BIN_ABXYZ". Chris@49: //! A is one of: I (for integral types) or F (for floating point types). Chris@49: //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types). Chris@49: //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes. Chris@49: template Chris@49: inline Chris@49: std::string Chris@49: diskio::gen_bin_header(const SpMat& x) Chris@49: { Chris@49: arma_type_check(( is_supported_elem_type::value == false )); Chris@49: Chris@49: arma_ignore(x); Chris@49: Chris@49: if(is_u8::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IU001"); Chris@49: } Chris@49: else Chris@49: if(is_s8::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IS001"); Chris@49: } Chris@49: else Chris@49: if(is_u16::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IU002"); Chris@49: } Chris@49: else Chris@49: if(is_s16::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IS002"); Chris@49: } Chris@49: else Chris@49: if(is_u32::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IU004"); Chris@49: } Chris@49: else Chris@49: if(is_s32::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IS004"); Chris@49: } Chris@49: #if defined(ARMA_USE_U64S64) Chris@49: else Chris@49: if(is_u64::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IU008"); Chris@49: } Chris@49: else Chris@49: if(is_s64::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IS008"); Chris@49: } Chris@49: #endif Chris@49: #if defined(ARMA_ALLOW_LONG) Chris@49: else Chris@49: if(is_ulng_t_32::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IU004"); Chris@49: } Chris@49: else Chris@49: if(is_slng_t_32::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IS004"); Chris@49: } Chris@49: else Chris@49: if(is_ulng_t_64::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IU008"); Chris@49: } Chris@49: else Chris@49: if(is_slng_t_64::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_IS008"); Chris@49: } Chris@49: #endif Chris@49: else Chris@49: if(is_float::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_FN004"); Chris@49: } Chris@49: else Chris@49: if(is_double::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_FN008"); Chris@49: } Chris@49: else Chris@49: if(is_complex_float::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_FC008"); Chris@49: } Chris@49: else Chris@49: if(is_complex_double::value == true) Chris@49: { Chris@49: return std::string("ARMA_SPM_BIN_FC016"); Chris@49: } Chris@49: else Chris@49: { Chris@49: return std::string(); Chris@49: } Chris@49: Chris@49: } Chris@49: Chris@49: Chris@49: //! Generate the first line of the header used for saving cubes in text format. Chris@49: //! Format: "ARMA_CUB_TXT_ABXYZ". Chris@49: //! A is one of: I (for integral types) or F (for floating point types). Chris@49: //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types). Chris@49: //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes. Chris@49: template Chris@49: inline Chris@49: std::string Chris@49: diskio::gen_txt_header(const Cube& x) Chris@49: { Chris@49: arma_type_check(( is_supported_elem_type::value == false )); Chris@49: Chris@49: arma_ignore(x); Chris@49: Chris@49: if(is_u8::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IU001"); Chris@49: } Chris@49: else Chris@49: if(is_s8::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IS001"); Chris@49: } Chris@49: else Chris@49: if(is_u16::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IU002"); Chris@49: } Chris@49: else Chris@49: if(is_s16::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IS002"); Chris@49: } Chris@49: else Chris@49: if(is_u32::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IU004"); Chris@49: } Chris@49: else Chris@49: if(is_s32::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IS004"); Chris@49: } Chris@49: #if defined(ARMA_USE_U64S64) Chris@49: else Chris@49: if(is_u64::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IU008"); Chris@49: } Chris@49: else Chris@49: if(is_s64::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IS008"); Chris@49: } Chris@49: #endif Chris@49: #if defined(ARMA_ALLOW_LONG) Chris@49: else Chris@49: if(is_ulng_t_32::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IU004"); Chris@49: } Chris@49: else Chris@49: if(is_slng_t_32::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IS004"); Chris@49: } Chris@49: else Chris@49: if(is_ulng_t_64::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IU008"); Chris@49: } Chris@49: else Chris@49: if(is_slng_t_64::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_IS008"); Chris@49: } Chris@49: #endif Chris@49: else Chris@49: if(is_float::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_FN004"); Chris@49: } Chris@49: else Chris@49: if(is_double::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_FN008"); Chris@49: } Chris@49: else Chris@49: if(is_complex_float::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_FC008"); Chris@49: } Chris@49: else Chris@49: if(is_complex_double::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_TXT_FC016"); Chris@49: } Chris@49: else Chris@49: { Chris@49: return std::string(); Chris@49: } Chris@49: Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Generate the first line of the header used for saving cubes in binary format. Chris@49: //! Format: "ARMA_CUB_BIN_ABXYZ". Chris@49: //! A is one of: I (for integral types) or F (for floating point types). Chris@49: //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types). Chris@49: //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes. Chris@49: template Chris@49: inline Chris@49: std::string Chris@49: diskio::gen_bin_header(const Cube& x) Chris@49: { Chris@49: arma_type_check(( is_supported_elem_type::value == false )); Chris@49: Chris@49: arma_ignore(x); Chris@49: Chris@49: if(is_u8::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IU001"); Chris@49: } Chris@49: else Chris@49: if(is_s8::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IS001"); Chris@49: } Chris@49: else Chris@49: if(is_u16::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IU002"); Chris@49: } Chris@49: else Chris@49: if(is_s16::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IS002"); Chris@49: } Chris@49: else Chris@49: if(is_u32::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IU004"); Chris@49: } Chris@49: else Chris@49: if(is_s32::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IS004"); Chris@49: } Chris@49: #if defined(ARMA_USE_U64S64) Chris@49: else Chris@49: if(is_u64::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IU008"); Chris@49: } Chris@49: else Chris@49: if(is_s64::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IS008"); Chris@49: } Chris@49: #endif Chris@49: #if defined(ARMA_ALLOW_LONG) Chris@49: else Chris@49: if(is_ulng_t_32::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IU004"); Chris@49: } Chris@49: else Chris@49: if(is_slng_t_32::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IS004"); Chris@49: } Chris@49: else Chris@49: if(is_ulng_t_64::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IU008"); Chris@49: } Chris@49: else Chris@49: if(is_slng_t_64::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_IS008"); Chris@49: } Chris@49: #endif Chris@49: else Chris@49: if(is_float::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_FN004"); Chris@49: } Chris@49: else Chris@49: if(is_double::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_FN008"); Chris@49: } Chris@49: else Chris@49: if(is_complex_float::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_FC008"); Chris@49: } Chris@49: else Chris@49: if(is_complex_double::value == true) Chris@49: { Chris@49: return std::string("ARMA_CUB_BIN_FC016"); Chris@49: } Chris@49: else Chris@49: { Chris@49: return std::string(); Chris@49: } Chris@49: Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: inline Chris@49: file_type Chris@49: diskio::guess_file_type(std::istream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: f.clear(); Chris@49: const std::fstream::pos_type pos1 = f.tellg(); Chris@49: Chris@49: f.clear(); Chris@49: f.seekg(0, ios::end); Chris@49: Chris@49: f.clear(); Chris@49: const std::fstream::pos_type pos2 = f.tellg(); Chris@49: Chris@49: const uword N = ( (pos1 >= 0) && (pos2 >= 0) ) ? uword(pos2 - pos1) : 0; Chris@49: Chris@49: f.clear(); Chris@49: f.seekg(pos1); Chris@49: Chris@49: podarray data(N); Chris@49: Chris@49: unsigned char* ptr = data.memptr(); Chris@49: Chris@49: f.clear(); Chris@49: f.read( reinterpret_cast(ptr), std::streamsize(N) ); Chris@49: Chris@49: const bool load_okay = f.good(); Chris@49: Chris@49: f.clear(); Chris@49: f.seekg(pos1); Chris@49: Chris@49: bool has_binary = false; Chris@49: bool has_comma = false; Chris@49: bool has_bracket = false; Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: uword i = 0; Chris@49: uword j = (N >= 2) ? 1 : 0; Chris@49: Chris@49: for(; j= 123)) || ((val_j <= 8) || (val_j >= 123)) ) Chris@49: { Chris@49: has_binary = true; Chris@49: break; Chris@49: } Chris@49: Chris@49: if( (val_i == ',') || (val_j == ',') ) Chris@49: { Chris@49: has_comma = true; Chris@49: } Chris@49: Chris@49: if( (val_i == '(') || (val_j == '(') || (val_i == ')') || (val_j == ')') ) Chris@49: { Chris@49: has_bracket = true; Chris@49: } Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: return file_type_unknown; Chris@49: } Chris@49: Chris@49: if(has_binary) Chris@49: { Chris@49: return raw_binary; Chris@49: } Chris@49: Chris@49: if(has_comma && (has_bracket == false)) Chris@49: { Chris@49: return csv_ascii; Chris@49: } Chris@49: Chris@49: return raw_ascii; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: inline Chris@49: char Chris@49: diskio::conv_to_hex_char(const u8 x) Chris@49: { Chris@49: char out; Chris@49: Chris@49: switch(x) Chris@49: { Chris@49: case 0: out = '0'; break; Chris@49: case 1: out = '1'; break; Chris@49: case 2: out = '2'; break; Chris@49: case 3: out = '3'; break; Chris@49: case 4: out = '4'; break; Chris@49: case 5: out = '5'; break; Chris@49: case 6: out = '6'; break; Chris@49: case 7: out = '7'; break; Chris@49: case 8: out = '8'; break; Chris@49: case 9: out = '9'; break; Chris@49: case 10: out = 'a'; break; Chris@49: case 11: out = 'b'; break; Chris@49: case 12: out = 'c'; break; Chris@49: case 13: out = 'd'; break; Chris@49: case 14: out = 'e'; break; Chris@49: case 15: out = 'f'; break; Chris@49: default: out = '-'; break; Chris@49: } Chris@49: Chris@49: return out; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: inline Chris@49: void Chris@49: diskio::conv_to_hex(char* out, const u8 x) Chris@49: { Chris@49: const u8 a = x / 16; Chris@49: const u8 b = x - 16*a; Chris@49: Chris@49: out[0] = conv_to_hex_char(a); Chris@49: out[1] = conv_to_hex_char(b); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Append a quasi-random string to the given filename. Chris@49: //! The rand() function is deliberately not used, Chris@49: //! as rand() has an internal state that changes Chris@49: //! from call to call. Such states should not be Chris@49: //! modified in scientific applications, where the Chris@49: //! results should be reproducable and not affected Chris@49: //! by saving data. Chris@49: inline Chris@49: std::string Chris@49: diskio::gen_tmp_name(const std::string& x) Chris@49: { Chris@49: const std::string* ptr_x = &x; Chris@49: const u8* ptr_ptr_x = reinterpret_cast(&ptr_x); Chris@49: Chris@49: const char* extra = ".tmp_"; Chris@49: const uword extra_size = 5; Chris@49: Chris@49: const uword tmp_size = 2*sizeof(u8*) + 2*2; Chris@49: char tmp[tmp_size]; Chris@49: Chris@49: uword char_count = 0; Chris@49: Chris@49: for(uword i=0; i(x.size()); Chris@49: u8 sum = 0; Chris@49: Chris@49: for(uword i=0; i Chris@49: inline Chris@49: bool Chris@49: diskio::convert_naninf(eT& val, const std::string& token) Chris@49: { Chris@49: // see if the token represents a NaN or Inf Chris@49: Chris@49: if( (token.length() == 3) || (token.length() == 4) ) Chris@49: { Chris@49: const bool neg = (token[0] == '-'); Chris@49: const bool pos = (token[0] == '+'); Chris@49: Chris@49: const size_t offset = ( (neg || pos) && (token.length() == 4) ) ? 1 : 0; Chris@49: Chris@49: const std::string token2 = token.substr(offset, 3); Chris@49: Chris@49: if( (token2 == "inf") || (token2 == "Inf") || (token2 == "INF") ) Chris@49: { Chris@49: val = neg ? -(Datum::inf) : Datum::inf; Chris@49: Chris@49: return true; Chris@49: } Chris@49: else Chris@49: if( (token2 == "nan") || (token2 == "Nan") || (token2 == "NaN") || (token2 == "NAN") ) Chris@49: { Chris@49: val = neg ? -(Datum::nan) : Datum::nan; Chris@49: Chris@49: return true; Chris@49: } Chris@49: } Chris@49: Chris@49: return false; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::convert_naninf(std::complex& val, const std::string& token) Chris@49: { Chris@49: if( token.length() >= 5 ) Chris@49: { Chris@49: std::stringstream ss( token.substr(1, token.length()-2) ); // strip '(' at the start and ')' at the end Chris@49: Chris@49: std::string token_real; Chris@49: std::string token_imag; Chris@49: Chris@49: std::getline(ss, token_real, ','); Chris@49: std::getline(ss, token_imag); Chris@49: Chris@49: std::stringstream ss_real(token_real); Chris@49: std::stringstream ss_imag(token_imag); Chris@49: Chris@49: T val_real = T(0); Chris@49: T val_imag = T(0); Chris@49: Chris@49: ss_real >> val_real; Chris@49: ss_imag >> val_imag; Chris@49: Chris@49: bool success_real = true; Chris@49: bool success_imag = true; Chris@49: Chris@49: if(ss_real.fail() == true) Chris@49: { Chris@49: success_real = diskio::convert_naninf( val_real, token_real ); Chris@49: } Chris@49: Chris@49: if(ss_imag.fail() == true) Chris@49: { Chris@49: success_imag = diskio::convert_naninf( val_imag, token_imag ); Chris@49: } Chris@49: Chris@49: val = std::complex(val_real, val_imag); Chris@49: Chris@49: return (success_real && success_imag); Chris@49: } Chris@49: Chris@49: return false; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix as raw text (no header, human readable). Chris@49: //! Matrices can be loaded in Matlab and Octave, as long as they don't have complex elements. Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_raw_ascii(const Mat& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::fstream f(tmp_name.c_str(), std::fstream::out); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_raw_ascii(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix as raw text (no header, human readable). Chris@49: //! Matrices can be loaded in Matlab and Octave, as long as they don't have complex elements. Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_raw_ascii(const Mat& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: uword cell_width; Chris@49: Chris@49: // TODO: need sane values for complex numbers Chris@49: Chris@49: if( (is_float::value == true) || (is_double::value == true) ) Chris@49: { Chris@49: f.setf(ios::scientific); Chris@49: f.precision(12); Chris@49: cell_width = 20; Chris@49: } Chris@49: Chris@49: for(uword row=0; row < x.n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < x.n_cols; ++col) Chris@49: { Chris@49: f.put(' '); Chris@49: Chris@49: if( (is_float::value == true) || (is_double::value == true) ) Chris@49: { Chris@49: f.width(cell_width); Chris@49: } Chris@49: Chris@49: f << x.at(row,col); Chris@49: } Chris@49: Chris@49: f.put('\n'); Chris@49: } Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix as raw binary (no header) Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_raw_binary(const Mat& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f(tmp_name.c_str(), std::fstream::binary); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_raw_binary(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_raw_binary(const Mat& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: f.write( reinterpret_cast(x.mem), std::streamsize(x.n_elem*sizeof(eT)) ); Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix in text format (human readable), Chris@49: //! with a header that indicates the matrix type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_ascii(const Mat& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f(tmp_name.c_str()); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_arma_ascii(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix in text format (human readable), Chris@49: //! with a header that indicates the matrix type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_ascii(const Mat& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const ios::fmtflags orig_flags = f.flags(); Chris@49: Chris@49: f << diskio::gen_txt_header(x) << '\n'; Chris@49: f << x.n_rows << ' ' << x.n_cols << '\n'; Chris@49: Chris@49: uword cell_width; Chris@49: Chris@49: // TODO: need sane values for complex numbers Chris@49: Chris@49: if( (is_float::value == true) || (is_double::value == true) ) Chris@49: { Chris@49: f.setf(ios::scientific); Chris@49: f.precision(12); Chris@49: cell_width = 20; Chris@49: } Chris@49: Chris@49: for(uword row=0; row < x.n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < x.n_cols; ++col) Chris@49: { Chris@49: f.put(' '); Chris@49: Chris@49: if( (is_float::value == true) || (is_double::value == true) ) Chris@49: { Chris@49: f.width(cell_width); Chris@49: } Chris@49: Chris@49: f << x.at(row,col); Chris@49: } Chris@49: Chris@49: f.put('\n'); Chris@49: } Chris@49: Chris@49: const bool save_okay = f.good(); Chris@49: Chris@49: f.flags(orig_flags); Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix in CSV text format (human readable) Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_csv_ascii(const Mat& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f(tmp_name.c_str()); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_csv_ascii(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix in CSV text format (human readable) Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_csv_ascii(const Mat& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const ios::fmtflags orig_flags = f.flags(); Chris@49: Chris@49: // TODO: need sane values for complex numbers Chris@49: Chris@49: if( (is_float::value == true) || (is_double::value == true) ) Chris@49: { Chris@49: f.setf(ios::scientific); Chris@49: f.precision(12); Chris@49: } Chris@49: Chris@49: uword x_n_rows = x.n_rows; Chris@49: uword x_n_cols = x.n_cols; Chris@49: Chris@49: for(uword row=0; row < x_n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < x_n_cols; ++col) Chris@49: { Chris@49: f << x.at(row,col); Chris@49: Chris@49: if( col < (x_n_cols-1) ) Chris@49: { Chris@49: f.put(','); Chris@49: } Chris@49: } Chris@49: Chris@49: f.put('\n'); Chris@49: } Chris@49: Chris@49: const bool save_okay = f.good(); Chris@49: Chris@49: f.flags(orig_flags); Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix in binary format, Chris@49: //! with a header that stores the matrix type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_binary(const Mat& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f(tmp_name.c_str(), std::fstream::binary); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_arma_binary(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix in binary format, Chris@49: //! with a header that stores the matrix type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_binary(const Mat& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: f << diskio::gen_bin_header(x) << '\n'; Chris@49: f << x.n_rows << ' ' << x.n_cols << '\n'; Chris@49: Chris@49: f.write( reinterpret_cast(x.mem), std::streamsize(x.n_elem*sizeof(eT)) ); Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix as a PGM greyscale image Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_pgm_binary(const Mat& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::fstream f(tmp_name.c_str(), std::fstream::out | std::fstream::binary); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_pgm_binary(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: // Chris@49: // TODO: Chris@49: // add functionality to save the image in a normalised format, Chris@49: // i.e. scaled so that every value falls in the [0,255] range. Chris@49: Chris@49: //! Save a matrix as a PGM greyscale image Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_pgm_binary(const Mat& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: f << "P5" << '\n'; Chris@49: f << x.n_cols << ' ' << x.n_rows << '\n'; Chris@49: f << 255 << '\n'; Chris@49: Chris@49: const uword n_elem = x.n_rows * x.n_cols; Chris@49: podarray tmp(n_elem); Chris@49: Chris@49: uword i = 0; Chris@49: Chris@49: for(uword row=0; row < x.n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < x.n_cols; ++col) Chris@49: { Chris@49: tmp[i] = u8( x.at(row,col) ); // TODO: add round() ? Chris@49: ++i; Chris@49: } Chris@49: } Chris@49: Chris@49: f.write(reinterpret_cast(tmp.mem), std::streamsize(n_elem) ); Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix as a PGM greyscale image Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_pgm_binary(const Mat< std::complex >& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const uchar_mat tmp = conv_to::from(x); Chris@49: Chris@49: return diskio::save_pgm_binary(tmp, final_name); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix as a PGM greyscale image Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_pgm_binary(const Mat< std::complex >& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const uchar_mat tmp = conv_to::from(x); Chris@49: Chris@49: return diskio::save_pgm_binary(tmp, f); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix as part of a HDF5 file Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_hdf5_binary(const Mat& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: #if defined(ARMA_USE_HDF5) Chris@49: { Chris@49: #if !defined(ARMA_PRINT_HDF5_ERRORS) Chris@49: { Chris@49: // Disable annoying HDF5 error messages. Chris@49: H5Eset_auto(H5E_DEFAULT, NULL, NULL); Chris@49: } Chris@49: #endif Chris@49: Chris@49: bool save_okay = false; Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: // Set up the file according to HDF5's preferences Chris@49: hid_t file = H5Fcreate(tmp_name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); Chris@49: Chris@49: // We need to create a dataset, datatype, and dataspace Chris@49: hsize_t dims[2]; Chris@49: dims[1] = x.n_rows; Chris@49: dims[0] = x.n_cols; Chris@49: Chris@49: hid_t dataspace = H5Screate_simple(2, dims, NULL); // treat the matrix as a 2d array dataspace Chris@49: hid_t datatype = hdf5_misc::get_hdf5_type(); Chris@49: Chris@49: // If this returned something invalid, well, it's time to crash. Chris@49: arma_check(datatype == -1, "Mat::save(): unknown datatype for HDF5"); Chris@49: Chris@49: // MATLAB forces the users to specify a name at save time for HDF5; Octave Chris@49: // will use the default of 'dataset' unless otherwise specified, so we will Chris@49: // use that. Chris@49: hid_t dataset = H5Dcreate(file, "dataset", datatype, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); Chris@49: Chris@49: // H5Dwrite does not make a distinction between row-major and column-major; Chris@49: // it just writes the memory. MATLAB and Octave store HDF5 matrices as Chris@49: // column-major, though, so we can save ours like that too and not need to Chris@49: // transpose. Chris@49: herr_t status = H5Dwrite(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, x.mem); Chris@49: save_okay = (status >= 0); Chris@49: Chris@49: H5Dclose(dataset); Chris@49: H5Tclose(datatype); Chris@49: H5Sclose(dataspace); Chris@49: H5Fclose(file); Chris@49: Chris@49: if(save_okay == true) { save_okay = diskio::safe_rename(tmp_name, final_name); } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: #else Chris@49: { Chris@49: arma_ignore(x); Chris@49: arma_ignore(final_name); Chris@49: Chris@49: arma_stop("Mat::save(): use of HDF5 needs to be enabled"); Chris@49: Chris@49: return false; Chris@49: } Chris@49: #endif Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a matrix as raw text (no header, human readable). Chris@49: //! Can read matrices saved as text in Matlab and Octave. Chris@49: //! NOTE: this is much slower than reading a file with a header. Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_raw_ascii(Mat& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::fstream f; Chris@49: f.open(name.c_str(), std::fstream::in); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_raw_ascii(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a matrix as raw text (no header, human readable). Chris@49: //! Can read matrices saved as text in Matlab and Octave. Chris@49: //! NOTE: this is much slower than reading a file with a header. Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_raw_ascii(Mat& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: bool load_okay = f.good(); Chris@49: Chris@49: f.clear(); Chris@49: const std::fstream::pos_type pos1 = f.tellg(); Chris@49: Chris@49: // Chris@49: // work out the size Chris@49: Chris@49: uword f_n_rows = 0; Chris@49: uword f_n_cols = 0; Chris@49: Chris@49: bool f_n_cols_found = false; Chris@49: Chris@49: std::string line_string; Chris@49: std::string token; Chris@49: Chris@49: std::stringstream line_stream; Chris@49: Chris@49: while( (f.good() == true) && (load_okay == true) ) Chris@49: { Chris@49: std::getline(f, line_string); Chris@49: Chris@49: if(line_string.size() == 0) Chris@49: { Chris@49: break; Chris@49: } Chris@49: Chris@49: line_stream.clear(); Chris@49: line_stream.str(line_string); Chris@49: Chris@49: uword line_n_cols = 0; Chris@49: Chris@49: while (line_stream >> token) Chris@49: { Chris@49: ++line_n_cols; Chris@49: } Chris@49: Chris@49: if(f_n_cols_found == false) Chris@49: { Chris@49: f_n_cols = line_n_cols; Chris@49: f_n_cols_found = true; Chris@49: } Chris@49: else Chris@49: { Chris@49: if(line_n_cols != f_n_cols) Chris@49: { Chris@49: err_msg = "inconsistent number of columns in "; Chris@49: load_okay = false; Chris@49: } Chris@49: } Chris@49: Chris@49: ++f_n_rows; Chris@49: } Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: f.clear(); Chris@49: f.seekg(pos1); Chris@49: Chris@49: x.set_size(f_n_rows, f_n_cols); Chris@49: Chris@49: std::stringstream ss; Chris@49: Chris@49: for(uword row=0; (row < x.n_rows) && (load_okay == true); ++row) Chris@49: { Chris@49: for(uword col=0; (col < x.n_cols) && (load_okay == true); ++col) Chris@49: { Chris@49: f >> token; Chris@49: Chris@49: ss.clear(); Chris@49: ss.str(token); Chris@49: Chris@49: eT val = eT(0); Chris@49: ss >> val; Chris@49: Chris@49: if(ss.fail() == false) Chris@49: { Chris@49: x.at(row,col) = val; Chris@49: } Chris@49: else Chris@49: { Chris@49: const bool success = diskio::convert_naninf( x.at(row,col), token ); Chris@49: Chris@49: if(success == false) Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "couldn't interpret data in "; Chris@49: } Chris@49: } Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: // an empty file indicates an empty matrix Chris@49: if( (f_n_cols_found == false) && (load_okay == true) ) Chris@49: { Chris@49: x.reset(); Chris@49: } Chris@49: Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a matrix in binary format (no header); Chris@49: //! the matrix is assumed to have one column Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_raw_binary(Mat& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::ifstream f; Chris@49: f.open(name.c_str(), std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_raw_binary(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_raw_binary(Mat& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: arma_ignore(err_msg); Chris@49: Chris@49: f.clear(); Chris@49: const std::streampos pos1 = f.tellg(); Chris@49: Chris@49: f.clear(); Chris@49: f.seekg(0, ios::end); Chris@49: Chris@49: f.clear(); Chris@49: const std::streampos pos2 = f.tellg(); Chris@49: Chris@49: const uword N = ( (pos1 >= 0) && (pos2 >= 0) ) ? uword(pos2 - pos1) : 0; Chris@49: Chris@49: f.clear(); Chris@49: //f.seekg(0, ios::beg); Chris@49: f.seekg(pos1); Chris@49: Chris@49: x.set_size(N / sizeof(eT), 1); Chris@49: Chris@49: f.clear(); Chris@49: f.read( reinterpret_cast(x.memptr()), std::streamsize(N) ); Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a matrix in text format (human readable), Chris@49: //! with a header that indicates the matrix type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_ascii(Mat& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::ifstream f(name.c_str()); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_arma_ascii(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a matrix in text format (human readable), Chris@49: //! with a header that indicates the matrix type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_ascii(Mat& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: bool load_okay = true; Chris@49: Chris@49: std::string f_header; Chris@49: uword f_n_rows; Chris@49: uword f_n_cols; Chris@49: Chris@49: f >> f_header; Chris@49: f >> f_n_rows; Chris@49: f >> f_n_cols; Chris@49: Chris@49: if(f_header == diskio::gen_txt_header(x)) Chris@49: { Chris@49: x.zeros(f_n_rows, f_n_cols); Chris@49: Chris@49: std::string token; Chris@49: std::stringstream ss; Chris@49: Chris@49: for(uword row=0; row < x.n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < x.n_cols; ++col) Chris@49: { Chris@49: f >> token; Chris@49: Chris@49: ss.clear(); Chris@49: ss.str(token); Chris@49: Chris@49: eT val = eT(0); Chris@49: ss >> val; Chris@49: Chris@49: if(ss.fail() == false) Chris@49: { Chris@49: x.at(row,col) = val; Chris@49: } Chris@49: else Chris@49: { Chris@49: diskio::convert_naninf( x.at(row,col), token ); Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: load_okay = f.good(); Chris@49: } Chris@49: else Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "incorrect header in "; Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a matrix in CSV text format (human readable) Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_csv_ascii(Mat& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::fstream f; Chris@49: f.open(name.c_str(), std::fstream::in); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_csv_ascii(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a matrix in CSV text format (human readable) Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_csv_ascii(Mat& x, std::istream& f, std::string&) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: bool load_okay = f.good(); Chris@49: Chris@49: f.clear(); Chris@49: const std::fstream::pos_type pos1 = f.tellg(); Chris@49: Chris@49: // Chris@49: // work out the size Chris@49: Chris@49: uword f_n_rows = 0; Chris@49: uword f_n_cols = 0; Chris@49: Chris@49: std::string line_string; Chris@49: std::string token; Chris@49: Chris@49: std::stringstream line_stream; Chris@49: Chris@49: while( (f.good() == true) && (load_okay == true) ) Chris@49: { Chris@49: std::getline(f, line_string); Chris@49: Chris@49: if(line_string.size() == 0) Chris@49: { Chris@49: break; Chris@49: } Chris@49: Chris@49: line_stream.clear(); Chris@49: line_stream.str(line_string); Chris@49: Chris@49: uword line_n_cols = 0; Chris@49: Chris@49: while(line_stream.good() == true) Chris@49: { Chris@49: std::getline(line_stream, token, ','); Chris@49: ++line_n_cols; Chris@49: } Chris@49: Chris@49: if(f_n_cols < line_n_cols) Chris@49: { Chris@49: f_n_cols = line_n_cols; Chris@49: } Chris@49: Chris@49: ++f_n_rows; Chris@49: } Chris@49: Chris@49: f.clear(); Chris@49: f.seekg(pos1); Chris@49: Chris@49: x.zeros(f_n_rows, f_n_cols); Chris@49: Chris@49: uword row = 0; Chris@49: Chris@49: std::stringstream ss; Chris@49: Chris@49: while(f.good() == true) Chris@49: { Chris@49: std::getline(f, line_string); Chris@49: Chris@49: if(line_string.size() == 0) Chris@49: { Chris@49: break; Chris@49: } Chris@49: Chris@49: line_stream.clear(); Chris@49: line_stream.str(line_string); Chris@49: Chris@49: uword col = 0; Chris@49: Chris@49: while(line_stream.good() == true) Chris@49: { Chris@49: std::getline(line_stream, token, ','); Chris@49: Chris@49: ss.clear(); Chris@49: ss.str(token); Chris@49: Chris@49: eT val = eT(0); Chris@49: ss >> val; Chris@49: Chris@49: if(ss.fail() == false) Chris@49: { Chris@49: x.at(row,col) = val; Chris@49: } Chris@49: else Chris@49: { Chris@49: diskio::convert_naninf( x.at(row,col), token ); Chris@49: } Chris@49: Chris@49: ++col; Chris@49: } Chris@49: Chris@49: ++row; Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a matrix in binary format, Chris@49: //! with a header that indicates the matrix type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_binary(Mat& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::ifstream f; Chris@49: f.open(name.c_str(), std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_arma_binary(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_binary(Mat& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: bool load_okay = true; Chris@49: Chris@49: std::string f_header; Chris@49: uword f_n_rows; Chris@49: uword f_n_cols; Chris@49: Chris@49: f >> f_header; Chris@49: f >> f_n_rows; Chris@49: f >> f_n_cols; Chris@49: Chris@49: if(f_header == diskio::gen_bin_header(x)) Chris@49: { Chris@49: //f.seekg(1, ios::cur); // NOTE: this may not be portable, as on a Windows machine a newline could be two characters Chris@49: f.get(); Chris@49: Chris@49: x.set_size(f_n_rows,f_n_cols); Chris@49: f.read( reinterpret_cast(x.memptr()), std::streamsize(x.n_elem*sizeof(eT)) ); Chris@49: Chris@49: load_okay = f.good(); Chris@49: } Chris@49: else Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "incorrect header in "; Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: inline Chris@49: void Chris@49: diskio::pnm_skip_comments(std::istream& f) Chris@49: { Chris@49: while( isspace(f.peek()) ) Chris@49: { Chris@49: while( isspace(f.peek()) ) Chris@49: { Chris@49: f.get(); Chris@49: } Chris@49: Chris@49: if(f.peek() == '#') Chris@49: { Chris@49: while( (f.peek() != '\r') && (f.peek()!='\n') ) Chris@49: { Chris@49: f.get(); Chris@49: } Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a PGM greyscale image as a matrix Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_pgm_binary(Mat& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::fstream f; Chris@49: f.open(name.c_str(), std::fstream::in | std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_pgm_binary(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a PGM greyscale image as a matrix Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_pgm_binary(Mat& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: bool load_okay = true; Chris@49: Chris@49: std::string f_header; Chris@49: f >> f_header; Chris@49: Chris@49: if(f_header == "P5") Chris@49: { Chris@49: uword f_n_rows = 0; Chris@49: uword f_n_cols = 0; Chris@49: int f_maxval = 0; Chris@49: Chris@49: diskio::pnm_skip_comments(f); Chris@49: Chris@49: f >> f_n_cols; Chris@49: diskio::pnm_skip_comments(f); Chris@49: Chris@49: f >> f_n_rows; Chris@49: diskio::pnm_skip_comments(f); Chris@49: Chris@49: f >> f_maxval; Chris@49: f.get(); Chris@49: Chris@49: if( (f_maxval > 0) || (f_maxval <= 65535) ) Chris@49: { Chris@49: x.set_size(f_n_rows,f_n_cols); Chris@49: Chris@49: if(f_maxval <= 255) Chris@49: { Chris@49: const uword n_elem = f_n_cols*f_n_rows; Chris@49: podarray tmp(n_elem); Chris@49: Chris@49: f.read( reinterpret_cast(tmp.memptr()), std::streamsize(n_elem) ); Chris@49: Chris@49: uword i = 0; Chris@49: Chris@49: //cout << "f_n_cols = " << f_n_cols << endl; Chris@49: //cout << "f_n_rows = " << f_n_rows << endl; Chris@49: Chris@49: Chris@49: for(uword row=0; row < f_n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < f_n_cols; ++col) Chris@49: { Chris@49: x.at(row,col) = eT(tmp[i]); Chris@49: ++i; Chris@49: } Chris@49: } Chris@49: Chris@49: } Chris@49: else Chris@49: { Chris@49: const uword n_elem = f_n_cols*f_n_rows; Chris@49: podarray tmp(n_elem); Chris@49: Chris@49: f.read( reinterpret_cast(tmp.memptr()), std::streamsize(n_elem*2) ); Chris@49: Chris@49: uword i = 0; Chris@49: Chris@49: for(uword row=0; row < f_n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < f_n_cols; ++col) Chris@49: { Chris@49: x.at(row,col) = eT(tmp[i]); Chris@49: ++i; Chris@49: } Chris@49: } Chris@49: Chris@49: } Chris@49: Chris@49: } Chris@49: else Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "currently no code available to handle loading "; Chris@49: } Chris@49: Chris@49: if(f.good() == false) Chris@49: { Chris@49: load_okay = false; Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "unsupported header in "; Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a PGM greyscale image as a matrix Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_pgm_binary(Mat< std::complex >& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: uchar_mat tmp; Chris@49: const bool load_okay = diskio::load_pgm_binary(tmp, name, err_msg); Chris@49: Chris@49: x = conv_to< Mat< std::complex > >::from(tmp); Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a PGM greyscale image as a matrix Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_pgm_binary(Mat< std::complex >& x, std::istream& is, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: uchar_mat tmp; Chris@49: const bool load_okay = diskio::load_pgm_binary(tmp, is, err_msg); Chris@49: Chris@49: x = conv_to< Mat< std::complex > >::from(tmp); Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a HDF5 file as a matrix Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_hdf5_binary(Mat& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: #if defined(ARMA_USE_HDF5) Chris@49: { Chris@49: Chris@49: // These may be necessary to store the error handler (if we need to). Chris@49: herr_t (*old_func)(hid_t, void*); Chris@49: void *old_client_data; Chris@49: Chris@49: #if !defined(ARMA_PRINT_HDF5_ERRORS) Chris@49: { Chris@49: // Save old error handler. Chris@49: H5Eget_auto(H5E_DEFAULT, &old_func, &old_client_data); Chris@49: Chris@49: // Disable annoying HDF5 error messages. Chris@49: H5Eset_auto(H5E_DEFAULT, NULL, NULL); Chris@49: } Chris@49: #endif Chris@49: Chris@49: bool load_okay = false; Chris@49: Chris@49: hid_t fid = H5Fopen(name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); Chris@49: Chris@49: if(fid >= 0) Chris@49: { Chris@49: // MATLAB HDF5 dataset names are user-specified; Chris@49: // Octave tends to store the datasets in a group, with the actual dataset being referred to as "value". Chris@49: // So we will search for "dataset" and "value", and if those are not found we will take the first dataset we do find. Chris@49: std::vector searchNames; Chris@49: searchNames.push_back("dataset"); Chris@49: searchNames.push_back("value"); Chris@49: Chris@49: hid_t dataset = hdf5_misc::search_hdf5_file(searchNames, fid, 2, false); Chris@49: Chris@49: if(dataset >= 0) Chris@49: { Chris@49: hid_t filespace = H5Dget_space(dataset); Chris@49: Chris@49: // This must be <= 2 due to our search rules. Chris@49: const int ndims = H5Sget_simple_extent_ndims(filespace); Chris@49: Chris@49: hsize_t dims[2]; Chris@49: const herr_t query_status = H5Sget_simple_extent_dims(filespace, dims, NULL); Chris@49: Chris@49: // arma_check(query_status < 0, "Mat::load(): cannot get size of HDF5 dataset"); Chris@49: if(query_status < 0) Chris@49: { Chris@49: err_msg = "cannot get size of HDF5 dataset in "; Chris@49: Chris@49: H5Sclose(filespace); Chris@49: H5Dclose(dataset); Chris@49: H5Fclose(fid); Chris@49: Chris@49: #if !defined(ARMA_PRINT_HDF5_ERRORS) Chris@49: { Chris@49: // Restore HDF5 error handler. Chris@49: H5Eset_auto(H5E_DEFAULT, old_func, old_client_data); Chris@49: } Chris@49: #endif Chris@49: Chris@49: return false; Chris@49: } Chris@49: Chris@49: if(ndims == 1) { dims[1] = 1; } // Vector case; fake second dimension (one column). Chris@49: Chris@49: x.set_size(dims[1], dims[0]); Chris@49: Chris@49: // Now we have to see what type is stored to figure out how to load it. Chris@49: hid_t datatype = H5Dget_type(dataset); Chris@49: hid_t mat_type = hdf5_misc::get_hdf5_type(); Chris@49: Chris@49: // If these are the same type, it is simple. Chris@49: if(H5Tequal(datatype, mat_type) > 0) Chris@49: { Chris@49: // Load directly; H5S_ALL used so that we load the entire dataset. Chris@49: hid_t read_status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, void_ptr(x.memptr())); Chris@49: Chris@49: if(read_status >= 0) { load_okay = true; } Chris@49: } Chris@49: else Chris@49: { Chris@49: // Load into another array and convert its type accordingly. Chris@49: hid_t read_status = hdf5_misc::load_and_convert_hdf5(x.memptr(), dataset, datatype, x.n_elem); Chris@49: Chris@49: if(read_status >= 0) { load_okay = true; } Chris@49: } Chris@49: Chris@49: // Now clean up. Chris@49: H5Tclose(datatype); Chris@49: H5Tclose(mat_type); Chris@49: H5Sclose(filespace); Chris@49: } Chris@49: Chris@49: H5Dclose(dataset); Chris@49: Chris@49: H5Fclose(fid); Chris@49: Chris@49: if(load_okay == false) Chris@49: { Chris@49: err_msg = "unsupported or incorrect HDF5 data in "; Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: err_msg = "cannot open file "; Chris@49: } Chris@49: Chris@49: #if !defined(ARMA_PRINT_HDF5_ERRORS) Chris@49: { Chris@49: // Restore HDF5 error handler. Chris@49: H5Eset_auto(H5E_DEFAULT, old_func, old_client_data); Chris@49: } Chris@49: #endif Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: #else Chris@49: { Chris@49: arma_ignore(x); Chris@49: arma_ignore(name); Chris@49: arma_ignore(err_msg); Chris@49: Chris@49: arma_stop("Mat::load(): use of HDF5 needs to be enabled"); Chris@49: Chris@49: return false; Chris@49: } Chris@49: #endif Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Try to load a matrix by automatically determining its type Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_auto_detect(Mat& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: #if defined(ARMA_USE_HDF5) Chris@49: // We're currently using the C bindings for the HDF5 library, which don't support C++ streams Chris@49: if( H5Fis_hdf5(name.c_str()) ) { return load_hdf5_binary(x, name, err_msg); } Chris@49: #endif Chris@49: Chris@49: std::fstream f; Chris@49: f.open(name.c_str(), std::fstream::in | std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_auto_detect(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Try to load a matrix by automatically determining its type Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_auto_detect(Mat& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: static const std::string ARMA_MAT_TXT = "ARMA_MAT_TXT"; Chris@49: static const std::string ARMA_MAT_BIN = "ARMA_MAT_BIN"; Chris@49: static const std::string P5 = "P5"; Chris@49: Chris@49: podarray raw_header(ARMA_MAT_TXT.length() + 1); Chris@49: Chris@49: std::streampos pos = f.tellg(); Chris@49: Chris@49: f.read( raw_header.memptr(), std::streamsize(ARMA_MAT_TXT.length()) ); Chris@49: raw_header[ARMA_MAT_TXT.length()] = '\0'; Chris@49: Chris@49: f.clear(); Chris@49: f.seekg(pos); Chris@49: Chris@49: const std::string header = raw_header.mem; Chris@49: Chris@49: if(ARMA_MAT_TXT == header.substr(0,ARMA_MAT_TXT.length())) Chris@49: { Chris@49: return load_arma_ascii(x, f, err_msg); Chris@49: } Chris@49: else Chris@49: if(ARMA_MAT_BIN == header.substr(0,ARMA_MAT_BIN.length())) Chris@49: { Chris@49: return load_arma_binary(x, f, err_msg); Chris@49: } Chris@49: else Chris@49: if(P5 == header.substr(0,P5.length())) Chris@49: { Chris@49: return load_pgm_binary(x, f, err_msg); Chris@49: } Chris@49: else Chris@49: { Chris@49: const file_type ft = guess_file_type(f); Chris@49: Chris@49: switch(ft) Chris@49: { Chris@49: case csv_ascii: Chris@49: return load_csv_ascii(x, f, err_msg); Chris@49: break; Chris@49: Chris@49: case raw_binary: Chris@49: return load_raw_binary(x, f, err_msg); Chris@49: break; Chris@49: Chris@49: case raw_ascii: Chris@49: return load_raw_ascii(x, f, err_msg); Chris@49: break; Chris@49: Chris@49: default: Chris@49: err_msg = "unknown data in "; Chris@49: return false; Chris@49: } Chris@49: } Chris@49: Chris@49: return false; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: // Chris@49: // sparse matrices Chris@49: // Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix in ASCII coord format Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_coord_ascii(const SpMat& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f(tmp_name.c_str()); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_coord_ascii(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix in ASCII coord format Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_coord_ascii(const SpMat& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const ios::fmtflags orig_flags = f.flags(); Chris@49: Chris@49: typename SpMat::const_iterator iter = x.begin(); Chris@49: typename SpMat::const_iterator iter_end = x.end(); Chris@49: Chris@49: for(; iter != iter_end; ++iter) Chris@49: { Chris@49: f.setf(ios::fixed); Chris@49: Chris@49: f << iter.row() << ' ' << iter.col() << ' '; Chris@49: Chris@49: if( (is_float::value == true) || (is_double::value == true) ) Chris@49: { Chris@49: f.setf(ios::scientific); Chris@49: f.precision(12); Chris@49: } Chris@49: Chris@49: f << (*iter) << '\n'; Chris@49: } Chris@49: Chris@49: Chris@49: // make sure it's possible to figure out the matrix size later Chris@49: if( (x.n_rows > 0) && (x.n_cols > 0) ) Chris@49: { Chris@49: const uword max_row = (x.n_rows > 0) ? x.n_rows-1 : 0; Chris@49: const uword max_col = (x.n_cols > 0) ? x.n_cols-1 : 0; Chris@49: Chris@49: if( x.at(max_row, max_col) == eT(0) ) Chris@49: { Chris@49: f.setf(ios::fixed); Chris@49: Chris@49: f << max_row << ' ' << max_col << " 0\n"; Chris@49: } Chris@49: } Chris@49: Chris@49: const bool save_okay = f.good(); Chris@49: Chris@49: f.flags(orig_flags); Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix in ASCII coord format (complex numbers) Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_coord_ascii(const SpMat< std::complex >& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const ios::fmtflags orig_flags = f.flags(); Chris@49: Chris@49: typedef typename std::complex eT; Chris@49: Chris@49: typename SpMat::const_iterator iter = x.begin(); Chris@49: typename SpMat::const_iterator iter_end = x.end(); Chris@49: Chris@49: for(; iter != iter_end; ++iter) Chris@49: { Chris@49: f.setf(ios::fixed); Chris@49: Chris@49: f << iter.row() << ' ' << iter.col() << ' '; Chris@49: Chris@49: if( (is_float::value == true) || (is_double::value == true) ) Chris@49: { Chris@49: f.setf(ios::scientific); Chris@49: f.precision(12); Chris@49: } Chris@49: Chris@49: const eT val = (*iter); Chris@49: Chris@49: f << val.real() << ' ' << val.imag() << '\n'; Chris@49: } Chris@49: Chris@49: // make sure it's possible to figure out the matrix size later Chris@49: if( (x.n_rows > 0) && (x.n_cols > 0) ) Chris@49: { Chris@49: const uword max_row = (x.n_rows > 0) ? x.n_rows-1 : 0; Chris@49: const uword max_col = (x.n_cols > 0) ? x.n_cols-1 : 0; Chris@49: Chris@49: if( x.at(max_row, max_col) == eT(0) ) Chris@49: { Chris@49: f.setf(ios::fixed); Chris@49: Chris@49: f << max_row << ' ' << max_col << " 0 0\n"; Chris@49: } Chris@49: } Chris@49: Chris@49: const bool save_okay = f.good(); Chris@49: Chris@49: f.flags(orig_flags); Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix in binary format, Chris@49: //! with a header that stores the matrix type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_binary(const SpMat& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f(tmp_name.c_str(), std::fstream::binary); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_arma_binary(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a matrix in binary format, Chris@49: //! with a header that stores the matrix type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_binary(const SpMat& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: f << diskio::gen_bin_header(x) << '\n'; Chris@49: f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_nonzero << '\n'; Chris@49: Chris@49: f.write( reinterpret_cast(x.values), std::streamsize(x.n_nonzero*sizeof(eT)) ); Chris@49: f.write( reinterpret_cast(x.row_indices), std::streamsize(x.n_nonzero*sizeof(uword)) ); Chris@49: f.write( reinterpret_cast(x.col_ptrs), std::streamsize((x.n_cols+1)*sizeof(uword)) ); Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_coord_ascii(SpMat& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::fstream f; Chris@49: f.open(name.c_str(), std::fstream::in | std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_coord_ascii(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_coord_ascii(SpMat& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: bool load_okay = f.good(); Chris@49: Chris@49: f.clear(); Chris@49: const std::fstream::pos_type pos1 = f.tellg(); Chris@49: Chris@49: // Chris@49: // work out the size Chris@49: Chris@49: uword f_n_rows = 0; Chris@49: uword f_n_cols = 0; Chris@49: uword f_n_nz = 0; Chris@49: Chris@49: bool size_found = false; Chris@49: Chris@49: std::string line_string; Chris@49: std::string token; Chris@49: Chris@49: std::stringstream line_stream; Chris@49: std::stringstream ss; Chris@49: Chris@49: uword last_line_row = 0; Chris@49: uword last_line_col = 0; Chris@49: Chris@49: bool first_line = true; Chris@49: bool weird_format = false; Chris@49: Chris@49: Chris@49: while( (f.good() == true) && (load_okay == true) ) Chris@49: { Chris@49: std::getline(f, line_string); Chris@49: Chris@49: if(line_string.size() == 0) Chris@49: { Chris@49: break; Chris@49: } Chris@49: Chris@49: line_stream.clear(); Chris@49: line_stream.str(line_string); Chris@49: Chris@49: uword line_row = 0; Chris@49: uword line_col = 0; Chris@49: Chris@49: // a valid line in co-ord format has at least 2 entries Chris@49: Chris@49: line_stream >> line_row; Chris@49: Chris@49: if(line_stream.good() == false) Chris@49: { Chris@49: load_okay = false; Chris@49: break; Chris@49: } Chris@49: Chris@49: line_stream >> line_col; Chris@49: Chris@49: size_found = true; Chris@49: Chris@49: if(f_n_rows < line_row) f_n_rows = line_row; Chris@49: if(f_n_cols < line_col) f_n_cols = line_col; Chris@49: Chris@49: if(first_line == true) Chris@49: { Chris@49: first_line = false; Chris@49: } Chris@49: else Chris@49: { Chris@49: if( (line_col < last_line_col) || ((line_row <= last_line_row) && (line_col <= last_line_col)) ) Chris@49: { Chris@49: weird_format = true; Chris@49: } Chris@49: } Chris@49: Chris@49: last_line_row = line_row; Chris@49: last_line_col = line_col; Chris@49: Chris@49: Chris@49: if(line_stream.good() == true) Chris@49: { Chris@49: eT final_val = eT(0); Chris@49: Chris@49: line_stream >> token; Chris@49: Chris@49: if(line_stream.fail() == false) Chris@49: { Chris@49: eT val = eT(0); Chris@49: Chris@49: ss.clear(); Chris@49: ss.str(token); Chris@49: Chris@49: ss >> val; Chris@49: Chris@49: if(ss.fail() == false) Chris@49: { Chris@49: final_val = val; Chris@49: } Chris@49: else Chris@49: { Chris@49: val = eT(0); Chris@49: Chris@49: const bool success = diskio::convert_naninf( val, token ); Chris@49: Chris@49: if(success == true) Chris@49: { Chris@49: final_val = val; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: if(final_val != eT(0)) Chris@49: { Chris@49: ++f_n_nz; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: if(size_found == true) Chris@49: { Chris@49: // take into account that indices start at 0 Chris@49: f_n_rows++; Chris@49: f_n_cols++; Chris@49: } Chris@49: Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: f.clear(); Chris@49: f.seekg(pos1); Chris@49: Chris@49: x.set_size(f_n_rows, f_n_cols); Chris@49: Chris@49: if(weird_format == false) Chris@49: { Chris@49: x.mem_resize(f_n_nz); Chris@49: } Chris@49: Chris@49: uword pos = 0; Chris@49: Chris@49: while(f.good() == true) Chris@49: { Chris@49: std::getline(f, line_string); Chris@49: Chris@49: if(line_string.size() == 0) Chris@49: { Chris@49: break; Chris@49: } Chris@49: Chris@49: line_stream.clear(); Chris@49: line_stream.str(line_string); Chris@49: Chris@49: uword line_row = 0; Chris@49: uword line_col = 0; Chris@49: Chris@49: line_stream >> line_row; Chris@49: line_stream >> line_col; Chris@49: Chris@49: eT final_val = eT(0); Chris@49: Chris@49: line_stream >> token; Chris@49: Chris@49: if(line_stream.fail() == false) Chris@49: { Chris@49: eT val = eT(0); Chris@49: Chris@49: ss.clear(); Chris@49: ss.str(token); Chris@49: Chris@49: ss >> val; Chris@49: Chris@49: if(ss.fail() == false) Chris@49: { Chris@49: final_val = val; Chris@49: } Chris@49: else Chris@49: { Chris@49: val = eT(0); Chris@49: Chris@49: const bool success = diskio::convert_naninf( val, token ); Chris@49: Chris@49: if(success == true) Chris@49: { Chris@49: final_val = val; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: if(final_val != eT(0)) Chris@49: { Chris@49: if(weird_format == false) Chris@49: { Chris@49: access::rw(x.row_indices[pos]) = line_row; Chris@49: access::rw(x.values[pos]) = final_val; Chris@49: ++access::rw(x.col_ptrs[line_col + 1]); Chris@49: Chris@49: ++pos; Chris@49: } Chris@49: else Chris@49: { Chris@49: x.at(line_row,line_col) = final_val; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: if(weird_format == false) Chris@49: { Chris@49: for(uword c = 1; c <= f_n_cols; ++c) Chris@49: { Chris@49: access::rw(x.col_ptrs[c]) += x.col_ptrs[c - 1]; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_coord_ascii(SpMat< std::complex >& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: bool load_okay = f.good(); Chris@49: Chris@49: f.clear(); Chris@49: const std::fstream::pos_type pos1 = f.tellg(); Chris@49: Chris@49: // Chris@49: // work out the size Chris@49: Chris@49: uword f_n_rows = 0; Chris@49: uword f_n_cols = 0; Chris@49: uword f_n_nz = 0; Chris@49: Chris@49: bool size_found = false; Chris@49: Chris@49: std::string line_string; Chris@49: std::string token_real; Chris@49: std::string token_imag; Chris@49: Chris@49: std::stringstream line_stream; Chris@49: std::stringstream ss; Chris@49: Chris@49: uword last_line_row = 0; Chris@49: uword last_line_col = 0; Chris@49: Chris@49: bool first_line = true; Chris@49: bool weird_format = false; Chris@49: Chris@49: while( (f.good() == true) && (load_okay == true) ) Chris@49: { Chris@49: std::getline(f, line_string); Chris@49: Chris@49: if(line_string.size() == 0) Chris@49: { Chris@49: break; Chris@49: } Chris@49: Chris@49: line_stream.clear(); Chris@49: line_stream.str(line_string); Chris@49: Chris@49: uword line_row = 0; Chris@49: uword line_col = 0; Chris@49: Chris@49: // a valid line in co-ord format has at least 2 entries Chris@49: Chris@49: line_stream >> line_row; Chris@49: Chris@49: if(line_stream.good() == false) Chris@49: { Chris@49: load_okay = false; Chris@49: break; Chris@49: } Chris@49: Chris@49: line_stream >> line_col; Chris@49: Chris@49: size_found = true; Chris@49: Chris@49: if(f_n_rows < line_row) f_n_rows = line_row; Chris@49: if(f_n_cols < line_col) f_n_cols = line_col; Chris@49: Chris@49: Chris@49: if(first_line == true) Chris@49: { Chris@49: first_line = false; Chris@49: } Chris@49: else Chris@49: { Chris@49: if( (line_col < last_line_col) || ((line_row <= last_line_row) && (line_col <= last_line_col)) ) Chris@49: { Chris@49: weird_format = true; Chris@49: } Chris@49: } Chris@49: Chris@49: last_line_row = line_row; Chris@49: last_line_col = line_col; Chris@49: Chris@49: Chris@49: if(line_stream.good() == true) Chris@49: { Chris@49: T final_val_real = T(0); Chris@49: T final_val_imag = T(0); Chris@49: Chris@49: Chris@49: line_stream >> token_real; Chris@49: Chris@49: if(line_stream.fail() == false) Chris@49: { Chris@49: T val_real = T(0); Chris@49: Chris@49: ss.clear(); Chris@49: ss.str(token_real); Chris@49: Chris@49: ss >> val_real; Chris@49: Chris@49: if(ss.fail() == false) Chris@49: { Chris@49: final_val_real = val_real; Chris@49: } Chris@49: else Chris@49: { Chris@49: val_real = T(0); Chris@49: Chris@49: const bool success = diskio::convert_naninf( val_real, token_real ); Chris@49: Chris@49: if(success == true) Chris@49: { Chris@49: final_val_real = val_real; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: line_stream >> token_imag; Chris@49: Chris@49: if(line_stream.fail() == false) Chris@49: { Chris@49: T val_imag = T(0); Chris@49: Chris@49: ss.clear(); Chris@49: ss.str(token_imag); Chris@49: Chris@49: ss >> val_imag; Chris@49: Chris@49: if(ss.fail() == false) Chris@49: { Chris@49: final_val_imag = val_imag; Chris@49: } Chris@49: else Chris@49: { Chris@49: val_imag = T(0); Chris@49: Chris@49: const bool success = diskio::convert_naninf( val_imag, token_imag ); Chris@49: Chris@49: if(success == true) Chris@49: { Chris@49: final_val_imag = val_imag; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: if( (final_val_real != T(0)) || (final_val_imag != T(0)) ) Chris@49: { Chris@49: ++f_n_nz; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: if(size_found == true) Chris@49: { Chris@49: // take into account that indices start at 0 Chris@49: f_n_rows++; Chris@49: f_n_cols++; Chris@49: } Chris@49: Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: f.clear(); Chris@49: f.seekg(pos1); Chris@49: Chris@49: x.set_size(f_n_rows, f_n_cols); Chris@49: Chris@49: if(weird_format == false) Chris@49: { Chris@49: x.mem_resize(f_n_nz); Chris@49: } Chris@49: Chris@49: uword pos = 0; Chris@49: Chris@49: while(f.good() == true) Chris@49: { Chris@49: std::getline(f, line_string); Chris@49: Chris@49: if(line_string.size() == 0) Chris@49: { Chris@49: break; Chris@49: } Chris@49: Chris@49: line_stream.clear(); Chris@49: line_stream.str(line_string); Chris@49: Chris@49: uword line_row = 0; Chris@49: uword line_col = 0; Chris@49: Chris@49: line_stream >> line_row; Chris@49: line_stream >> line_col; Chris@49: Chris@49: T final_val_real = T(0); Chris@49: T final_val_imag = T(0); Chris@49: Chris@49: Chris@49: line_stream >> token_real; Chris@49: Chris@49: if(line_stream.fail() == false) Chris@49: { Chris@49: T val_real = T(0); Chris@49: Chris@49: ss.clear(); Chris@49: ss.str(token_real); Chris@49: Chris@49: ss >> val_real; Chris@49: Chris@49: if(ss.fail() == false) Chris@49: { Chris@49: final_val_real = val_real; Chris@49: } Chris@49: else Chris@49: { Chris@49: val_real = T(0); Chris@49: Chris@49: const bool success = diskio::convert_naninf( val_real, token_real ); Chris@49: Chris@49: if(success == true) Chris@49: { Chris@49: final_val_real = val_real; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: line_stream >> token_imag; Chris@49: Chris@49: if(line_stream.fail() == false) Chris@49: { Chris@49: T val_imag = T(0); Chris@49: Chris@49: ss.clear(); Chris@49: ss.str(token_imag); Chris@49: Chris@49: ss >> val_imag; Chris@49: Chris@49: if(ss.fail() == false) Chris@49: { Chris@49: final_val_imag = val_imag; Chris@49: } Chris@49: else Chris@49: { Chris@49: val_imag = T(0); Chris@49: Chris@49: const bool success = diskio::convert_naninf( val_imag, token_imag ); Chris@49: Chris@49: if(success == true) Chris@49: { Chris@49: final_val_imag = val_imag; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: if( (final_val_real != T(0)) || (final_val_imag != T(0)) ) Chris@49: { Chris@49: if(weird_format == false) Chris@49: { Chris@49: access::rw(x.row_indices[pos]) = line_row; Chris@49: access::rw(x.values[pos]) = std::complex(final_val_real, final_val_imag); Chris@49: ++access::rw(x.col_ptrs[line_col + 1]); Chris@49: Chris@49: ++pos; Chris@49: } Chris@49: else Chris@49: { Chris@49: x.at(line_row,line_col) = std::complex(final_val_real, final_val_imag); Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: if(weird_format == false) Chris@49: { Chris@49: for(uword c = 1; c <= f_n_cols; ++c) Chris@49: { Chris@49: access::rw(x.col_ptrs[c]) += x.col_ptrs[c - 1]; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a matrix in binary format, Chris@49: //! with a header that indicates the matrix type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_binary(SpMat& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::ifstream f; Chris@49: f.open(name.c_str(), std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_arma_binary(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_binary(SpMat& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: bool load_okay = true; Chris@49: Chris@49: std::string f_header; Chris@49: Chris@49: f >> f_header; Chris@49: Chris@49: if(f_header == diskio::gen_bin_header(x)) Chris@49: { Chris@49: uword f_n_rows; Chris@49: uword f_n_cols; Chris@49: uword f_n_nz; Chris@49: Chris@49: f >> f_n_rows; Chris@49: f >> f_n_cols; Chris@49: f >> f_n_nz; Chris@49: Chris@49: //f.seekg(1, ios::cur); // NOTE: this may not be portable, as on a Windows machine a newline could be two characters Chris@49: f.get(); Chris@49: Chris@49: x.set_size(f_n_rows, f_n_cols); Chris@49: Chris@49: x.mem_resize(f_n_nz); Chris@49: Chris@49: f.read( reinterpret_cast(access::rwp(x.values)), std::streamsize(x.n_nonzero*sizeof(eT)) ); Chris@49: f.read( reinterpret_cast(access::rwp(x.row_indices)), std::streamsize(x.n_nonzero*sizeof(uword)) ); Chris@49: f.read( reinterpret_cast(access::rwp(x.col_ptrs)), std::streamsize((x.n_cols+1)*sizeof(uword)) ); Chris@49: Chris@49: load_okay = f.good(); Chris@49: } Chris@49: else Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "incorrect header in "; Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: // cubes Chris@49: Chris@49: Chris@49: Chris@49: //! Save a cube as raw text (no header, human readable). Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_raw_ascii(const Cube& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::fstream f(tmp_name.c_str(), std::fstream::out); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = save_raw_ascii(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a cube as raw text (no header, human readable). Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_raw_ascii(const Cube& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: uword cell_width; Chris@49: Chris@49: // TODO: need sane values for complex numbers Chris@49: Chris@49: if( (is_float::value == true) || (is_double::value == true) ) Chris@49: { Chris@49: f.setf(ios::scientific); Chris@49: f.precision(12); Chris@49: cell_width = 20; Chris@49: } Chris@49: Chris@49: for(uword slice=0; slice < x.n_slices; ++slice) Chris@49: { Chris@49: for(uword row=0; row < x.n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < x.n_cols; ++col) Chris@49: { Chris@49: f.put(' '); Chris@49: Chris@49: if( (is_float::value == true) || (is_double::value == true) ) Chris@49: { Chris@49: f.width(cell_width); Chris@49: } Chris@49: Chris@49: f << x.at(row,col,slice); Chris@49: } Chris@49: Chris@49: f.put('\n'); Chris@49: } Chris@49: } Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a cube as raw binary (no header) Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_raw_binary(const Cube& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f(tmp_name.c_str(), std::fstream::binary); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_raw_binary(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_raw_binary(const Cube& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: f.write( reinterpret_cast(x.mem), std::streamsize(x.n_elem*sizeof(eT)) ); Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a cube in text format (human readable), Chris@49: //! with a header that indicates the cube type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_ascii(const Cube& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f(tmp_name.c_str()); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_arma_ascii(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a cube in text format (human readable), Chris@49: //! with a header that indicates the cube type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_ascii(const Cube& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const ios::fmtflags orig_flags = f.flags(); Chris@49: Chris@49: f << diskio::gen_txt_header(x) << '\n'; Chris@49: f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n'; Chris@49: Chris@49: uword cell_width; Chris@49: Chris@49: // TODO: need sane values for complex numbers Chris@49: Chris@49: if( (is_float::value == true) || (is_double::value == true) ) Chris@49: { Chris@49: f.setf(ios::scientific); Chris@49: f.precision(12); Chris@49: cell_width = 20; Chris@49: } Chris@49: Chris@49: for(uword slice=0; slice < x.n_slices; ++slice) Chris@49: { Chris@49: for(uword row=0; row < x.n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < x.n_cols; ++col) Chris@49: { Chris@49: f.put(' '); Chris@49: Chris@49: if( (is_float::value == true) || (is_double::value == true) ) Chris@49: { Chris@49: f.width(cell_width); Chris@49: } Chris@49: Chris@49: f << x.at(row,col,slice); Chris@49: } Chris@49: Chris@49: f.put('\n'); Chris@49: } Chris@49: } Chris@49: Chris@49: const bool save_okay = f.good(); Chris@49: Chris@49: f.flags(orig_flags); Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a cube in binary format, Chris@49: //! with a header that stores the cube type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_binary(const Cube& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f(tmp_name.c_str(), std::fstream::binary); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_arma_binary(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a cube in binary format, Chris@49: //! with a header that stores the cube type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_binary(const Cube& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: f << diskio::gen_bin_header(x) << '\n'; Chris@49: f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n'; Chris@49: Chris@49: f.write( reinterpret_cast(x.mem), std::streamsize(x.n_elem*sizeof(eT)) ); Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Save a cube as part of a HDF5 file Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_hdf5_binary(const Cube& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: #if defined(ARMA_USE_HDF5) Chris@49: { Chris@49: #if !defined(ARMA_PRINT_HDF5_ERRORS) Chris@49: { Chris@49: // Disable annoying HDF5 error messages. Chris@49: H5Eset_auto(H5E_DEFAULT, NULL, NULL); Chris@49: } Chris@49: #endif Chris@49: Chris@49: bool save_okay = false; Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: // Set up the file according to HDF5's preferences Chris@49: hid_t file = H5Fcreate(tmp_name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); Chris@49: Chris@49: // We need to create a dataset, datatype, and dataspace Chris@49: hsize_t dims[3]; Chris@49: dims[2] = x.n_rows; Chris@49: dims[1] = x.n_cols; Chris@49: dims[0] = x.n_slices; Chris@49: Chris@49: hid_t dataspace = H5Screate_simple(3, dims, NULL); // treat the cube as a 3d array dataspace Chris@49: hid_t datatype = hdf5_misc::get_hdf5_type(); Chris@49: Chris@49: // If this returned something invalid, well, it's time to crash. Chris@49: arma_check(datatype == -1, "Cube::save(): unknown datatype for HDF5"); Chris@49: Chris@49: // MATLAB forces the users to specify a name at save time for HDF5; Octave Chris@49: // will use the default of 'dataset' unless otherwise specified, so we will Chris@49: // use that. Chris@49: hid_t dataset = H5Dcreate(file, "dataset", datatype, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); Chris@49: Chris@49: herr_t status = H5Dwrite(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, x.mem); Chris@49: save_okay = (status >= 0); Chris@49: Chris@49: H5Dclose(dataset); Chris@49: H5Tclose(datatype); Chris@49: H5Sclose(dataspace); Chris@49: H5Fclose(file); Chris@49: Chris@49: if(save_okay == true) { save_okay = diskio::safe_rename(tmp_name, final_name); } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: #else Chris@49: { Chris@49: arma_ignore(x); Chris@49: arma_ignore(final_name); Chris@49: Chris@49: arma_stop("Cube::save(): use of HDF5 needs to be enabled"); Chris@49: Chris@49: return false; Chris@49: } Chris@49: #endif Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a cube as raw text (no header, human readable). Chris@49: //! NOTE: this is much slower than reading a file with a header. Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_raw_ascii(Cube& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: Mat tmp; Chris@49: const bool load_okay = diskio::load_raw_ascii(tmp, name, err_msg); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: if(tmp.is_empty() == false) Chris@49: { Chris@49: x.set_size(tmp.n_rows, tmp.n_cols, 1); Chris@49: Chris@49: x.slice(0) = tmp; Chris@49: } Chris@49: else Chris@49: { Chris@49: x.reset(); Chris@49: } Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a cube as raw text (no header, human readable). Chris@49: //! NOTE: this is much slower than reading a file with a header. Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_raw_ascii(Cube& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: Mat tmp; Chris@49: const bool load_okay = diskio::load_raw_ascii(tmp, f, err_msg); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: if(tmp.is_empty() == false) Chris@49: { Chris@49: x.set_size(tmp.n_rows, tmp.n_cols, 1); Chris@49: Chris@49: x.slice(0) = tmp; Chris@49: } Chris@49: else Chris@49: { Chris@49: x.reset(); Chris@49: } Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a cube in binary format (no header); Chris@49: //! the cube is assumed to have one slice with one column Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_raw_binary(Cube& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::ifstream f; Chris@49: f.open(name.c_str(), std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_raw_binary(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_raw_binary(Cube& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: arma_ignore(err_msg); Chris@49: Chris@49: f.clear(); Chris@49: const std::streampos pos1 = f.tellg(); Chris@49: Chris@49: f.clear(); Chris@49: f.seekg(0, ios::end); Chris@49: Chris@49: f.clear(); Chris@49: const std::streampos pos2 = f.tellg(); Chris@49: Chris@49: const uword N = ( (pos1 >= 0) && (pos2 >= 0) ) ? uword(pos2 - pos1) : 0; Chris@49: Chris@49: f.clear(); Chris@49: //f.seekg(0, ios::beg); Chris@49: f.seekg(pos1); Chris@49: Chris@49: x.set_size(N / sizeof(eT), 1, 1); Chris@49: Chris@49: f.clear(); Chris@49: f.read( reinterpret_cast(x.memptr()), std::streamsize(N) ); Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a cube in text format (human readable), Chris@49: //! with a header that indicates the cube type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_ascii(Cube& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::ifstream f(name.c_str()); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_arma_ascii(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a cube in text format (human readable), Chris@49: //! with a header that indicates the cube type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_ascii(Cube& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: bool load_okay = true; Chris@49: Chris@49: std::string f_header; Chris@49: uword f_n_rows; Chris@49: uword f_n_cols; Chris@49: uword f_n_slices; Chris@49: Chris@49: f >> f_header; Chris@49: f >> f_n_rows; Chris@49: f >> f_n_cols; Chris@49: f >> f_n_slices; Chris@49: Chris@49: if(f_header == diskio::gen_txt_header(x)) Chris@49: { Chris@49: x.set_size(f_n_rows, f_n_cols, f_n_slices); Chris@49: Chris@49: for(uword slice=0; slice < x.n_slices; ++slice) Chris@49: { Chris@49: for(uword row=0; row < x.n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < x.n_cols; ++col) Chris@49: { Chris@49: f >> x.at(row,col,slice); Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: load_okay = f.good(); Chris@49: } Chris@49: else Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "incorrect header in "; Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a cube in binary format, Chris@49: //! with a header that indicates the cube type as well as its dimensions Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_binary(Cube& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::ifstream f; Chris@49: f.open(name.c_str(), std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_arma_binary(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_binary(Cube& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: bool load_okay = true; Chris@49: Chris@49: std::string f_header; Chris@49: uword f_n_rows; Chris@49: uword f_n_cols; Chris@49: uword f_n_slices; Chris@49: Chris@49: f >> f_header; Chris@49: f >> f_n_rows; Chris@49: f >> f_n_cols; Chris@49: f >> f_n_slices; Chris@49: Chris@49: if(f_header == diskio::gen_bin_header(x)) Chris@49: { Chris@49: //f.seekg(1, ios::cur); // NOTE: this may not be portable, as on a Windows machine a newline could be two characters Chris@49: f.get(); Chris@49: Chris@49: x.set_size(f_n_rows, f_n_cols, f_n_slices); Chris@49: f.read( reinterpret_cast(x.memptr()), std::streamsize(x.n_elem*sizeof(eT)) ); Chris@49: Chris@49: load_okay = f.good(); Chris@49: } Chris@49: else Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "incorrect header in "; Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Load a HDF5 file as a cube Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_hdf5_binary(Cube& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: #if defined(ARMA_USE_HDF5) Chris@49: { Chris@49: Chris@49: // These may be necessary to store the error handler (if we need to). Chris@49: herr_t (*old_func)(hid_t, void*); Chris@49: void *old_client_data; Chris@49: Chris@49: #if !defined(ARMA_PRINT_HDF5_ERRORS) Chris@49: { Chris@49: // Save old error handler. Chris@49: H5Eget_auto(H5E_DEFAULT, &old_func, &old_client_data); Chris@49: Chris@49: // Disable annoying HDF5 error messages. Chris@49: H5Eset_auto(H5E_DEFAULT, NULL, NULL); Chris@49: } Chris@49: #endif Chris@49: Chris@49: bool load_okay = false; Chris@49: Chris@49: hid_t fid = H5Fopen(name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); Chris@49: Chris@49: if(fid >= 0) Chris@49: { Chris@49: // MATLAB HDF5 dataset names are user-specified; Chris@49: // Octave tends to store the datasets in a group, with the actual dataset being referred to as "value". Chris@49: // So we will search for "dataset" and "value", and if those are not found we will take the first dataset we do find. Chris@49: std::vector searchNames; Chris@49: searchNames.push_back("dataset"); Chris@49: searchNames.push_back("value"); Chris@49: Chris@49: hid_t dataset = hdf5_misc::search_hdf5_file(searchNames, fid, 3, false); Chris@49: Chris@49: if(dataset >= 0) Chris@49: { Chris@49: hid_t filespace = H5Dget_space(dataset); Chris@49: Chris@49: // This must be <= 3 due to our search rules. Chris@49: const int ndims = H5Sget_simple_extent_ndims(filespace); Chris@49: Chris@49: hsize_t dims[3]; Chris@49: const herr_t query_status = H5Sget_simple_extent_dims(filespace, dims, NULL); Chris@49: Chris@49: // arma_check(query_status < 0, "Cube::load(): cannot get size of HDF5 dataset"); Chris@49: if(query_status < 0) Chris@49: { Chris@49: err_msg = "cannot get size of HDF5 dataset in "; Chris@49: Chris@49: H5Sclose(filespace); Chris@49: H5Dclose(dataset); Chris@49: H5Fclose(fid); Chris@49: Chris@49: #if !defined(ARMA_PRINT_HDF5_ERRORS) Chris@49: { Chris@49: // Restore HDF5 error handler. Chris@49: H5Eset_auto(H5E_DEFAULT, old_func, old_client_data); Chris@49: } Chris@49: #endif Chris@49: Chris@49: return false; Chris@49: } Chris@49: Chris@49: if (ndims == 1) { dims[1] = 1; dims[2] = 1; } // Vector case; one row/colum, several slices Chris@49: if (ndims == 2) { dims[2] = 1; } // Matrix case; one column, several rows/slices Chris@49: Chris@49: x.set_size(dims[2], dims[1], dims[0]); Chris@49: Chris@49: // Now we have to see what type is stored to figure out how to load it. Chris@49: hid_t datatype = H5Dget_type(dataset); Chris@49: hid_t mat_type = hdf5_misc::get_hdf5_type(); Chris@49: Chris@49: // If these are the same type, it is simple. Chris@49: if(H5Tequal(datatype, mat_type) > 0) Chris@49: { Chris@49: // Load directly; H5S_ALL used so that we load the entire dataset. Chris@49: hid_t read_status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, void_ptr(x.memptr())); Chris@49: Chris@49: if(read_status >= 0) { load_okay = true; } Chris@49: } Chris@49: else Chris@49: { Chris@49: // Load into another array and convert its type accordingly. Chris@49: hid_t read_status = hdf5_misc::load_and_convert_hdf5(x.memptr(), dataset, datatype, x.n_elem); Chris@49: Chris@49: if(read_status >= 0) { load_okay = true; } Chris@49: } Chris@49: Chris@49: // Now clean up. Chris@49: H5Tclose(datatype); Chris@49: H5Tclose(mat_type); Chris@49: H5Sclose(filespace); Chris@49: } Chris@49: Chris@49: H5Dclose(dataset); Chris@49: Chris@49: H5Fclose(fid); Chris@49: Chris@49: if(load_okay == false) Chris@49: { Chris@49: err_msg = "unsupported or incorrect HDF5 data in "; Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: err_msg = "cannot open file "; Chris@49: } Chris@49: Chris@49: #if !defined(ARMA_PRINT_HDF5_ERRORS) Chris@49: { Chris@49: // Restore HDF5 error handler. Chris@49: H5Eset_auto(H5E_DEFAULT, old_func, old_client_data); Chris@49: } Chris@49: #endif Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: #else Chris@49: { Chris@49: arma_ignore(x); Chris@49: arma_ignore(name); Chris@49: arma_ignore(err_msg); Chris@49: Chris@49: arma_stop("Cube::load(): use of HDF5 needs to be enabled"); Chris@49: Chris@49: return false; Chris@49: } Chris@49: #endif Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Try to load a cube by automatically determining its type Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_auto_detect(Cube& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: #if defined(ARMA_USE_HDF5) Chris@49: // We're currently using the C bindings for the HDF5 library, which don't support C++ streams Chris@49: if( H5Fis_hdf5(name.c_str()) ) { return load_hdf5_binary(x, name, err_msg); } Chris@49: #endif Chris@49: Chris@49: std::fstream f; Chris@49: f.open(name.c_str(), std::fstream::in | std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_auto_detect(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Try to load a cube by automatically determining its type Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_auto_detect(Cube& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: static const std::string ARMA_CUB_TXT = "ARMA_CUB_TXT"; Chris@49: static const std::string ARMA_CUB_BIN = "ARMA_CUB_BIN"; Chris@49: static const std::string P6 = "P6"; Chris@49: Chris@49: podarray raw_header(ARMA_CUB_TXT.length() + 1); Chris@49: Chris@49: std::streampos pos = f.tellg(); Chris@49: Chris@49: f.read( raw_header.memptr(), std::streamsize(ARMA_CUB_TXT.length()) ); Chris@49: raw_header[ARMA_CUB_TXT.length()] = '\0'; Chris@49: Chris@49: f.clear(); Chris@49: f.seekg(pos); Chris@49: Chris@49: const std::string header = raw_header.mem; Chris@49: Chris@49: if(ARMA_CUB_TXT == header.substr(0, ARMA_CUB_TXT.length())) Chris@49: { Chris@49: return load_arma_ascii(x, f, err_msg); Chris@49: } Chris@49: else Chris@49: if(ARMA_CUB_BIN == header.substr(0, ARMA_CUB_BIN.length())) Chris@49: { Chris@49: return load_arma_binary(x, f, err_msg); Chris@49: } Chris@49: else Chris@49: if(P6 == header.substr(0, P6.length())) Chris@49: { Chris@49: return load_ppm_binary(x, f, err_msg); Chris@49: } Chris@49: else Chris@49: { Chris@49: const file_type ft = guess_file_type(f); Chris@49: Chris@49: switch(ft) Chris@49: { Chris@49: // case csv_ascii: Chris@49: // return load_csv_ascii(x, f, err_msg); Chris@49: // break; Chris@49: Chris@49: case raw_binary: Chris@49: return load_raw_binary(x, f, err_msg); Chris@49: break; Chris@49: Chris@49: case raw_ascii: Chris@49: return load_raw_ascii(x, f, err_msg); Chris@49: break; Chris@49: Chris@49: default: Chris@49: err_msg = "unknown data in "; Chris@49: return false; Chris@49: } Chris@49: } Chris@49: Chris@49: return false; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: Chris@49: Chris@49: // fields Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_binary(const field& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f( tmp_name.c_str(), std::fstream::binary ); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_arma_binary(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_arma_binary(const field& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: arma_type_check(( (is_Mat::value == false) && (is_Cube::value == false) )); Chris@49: Chris@49: f << "ARMA_FLD_BIN" << '\n'; Chris@49: f << x.n_rows << '\n'; Chris@49: f << x.n_cols << '\n'; Chris@49: Chris@49: bool save_okay = true; Chris@49: Chris@49: for(uword i=0; i Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_binary(field& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::ifstream f( name.c_str(), std::fstream::binary ); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_arma_binary(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_arma_binary(field& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: arma_type_check(( (is_Mat::value == false) && (is_Cube::value == false) )); Chris@49: Chris@49: bool load_okay = true; Chris@49: Chris@49: std::string f_type; Chris@49: f >> f_type; Chris@49: Chris@49: if(f_type != "ARMA_FLD_BIN") Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "unsupported field type in "; Chris@49: } Chris@49: else Chris@49: { Chris@49: uword f_n_rows; Chris@49: uword f_n_cols; Chris@49: Chris@49: f >> f_n_rows; Chris@49: f >> f_n_cols; Chris@49: Chris@49: x.set_size(f_n_rows, f_n_cols); Chris@49: Chris@49: f.get(); Chris@49: Chris@49: for(uword i=0; i& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f( tmp_name.c_str(), std::fstream::binary ); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_std_string(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: inline Chris@49: bool Chris@49: diskio::save_std_string(const field& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: for(uword row=0; row& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::ifstream f( name.c_str() ); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_std_string(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: inline Chris@49: bool Chris@49: diskio::load_std_string(field& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: bool load_okay = true; Chris@49: Chris@49: // Chris@49: // work out the size Chris@49: Chris@49: uword f_n_rows = 0; Chris@49: uword f_n_cols = 0; Chris@49: Chris@49: bool f_n_cols_found = false; Chris@49: Chris@49: std::string line_string; Chris@49: std::string token; Chris@49: Chris@49: while( (f.good() == true) && (load_okay == true) ) Chris@49: { Chris@49: std::getline(f, line_string); Chris@49: if(line_string.size() == 0) Chris@49: break; Chris@49: Chris@49: std::stringstream line_stream(line_string); Chris@49: Chris@49: uword line_n_cols = 0; Chris@49: while (line_stream >> token) Chris@49: line_n_cols++; Chris@49: Chris@49: if(f_n_cols_found == false) Chris@49: { Chris@49: f_n_cols = line_n_cols; Chris@49: f_n_cols_found = true; Chris@49: } Chris@49: else Chris@49: { Chris@49: if(line_n_cols != f_n_cols) Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "inconsistent number of columns in "; Chris@49: } Chris@49: } Chris@49: Chris@49: ++f_n_rows; Chris@49: } Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: f.clear(); Chris@49: f.seekg(0, ios::beg); Chris@49: //f.seekg(start); Chris@49: Chris@49: x.set_size(f_n_rows, f_n_cols); Chris@49: Chris@49: for(uword row=0; row < x.n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < x.n_cols; ++col) Chris@49: { Chris@49: f >> x.at(row,col); Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: if(f.good() == false) Chris@49: { Chris@49: load_okay = false; Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Try to load a field by automatically determining its type Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_auto_detect(field& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::fstream f; Chris@49: f.open(name.c_str(), std::fstream::in | std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_auto_detect(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! Try to load a field by automatically determining its type Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_auto_detect(field& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: arma_type_check(( is_Mat::value == false )); Chris@49: Chris@49: static const std::string ARMA_FLD_BIN = "ARMA_FLD_BIN"; Chris@49: static const std::string P6 = "P6"; Chris@49: Chris@49: podarray raw_header(ARMA_FLD_BIN.length() + 1); Chris@49: Chris@49: std::streampos pos = f.tellg(); Chris@49: Chris@49: f.read( raw_header.memptr(), std::streamsize(ARMA_FLD_BIN.length()) ); Chris@49: Chris@49: f.clear(); Chris@49: f.seekg(pos); Chris@49: Chris@49: raw_header[ARMA_FLD_BIN.length()] = '\0'; Chris@49: Chris@49: const std::string header = raw_header.mem; Chris@49: Chris@49: if(ARMA_FLD_BIN == header.substr(0, ARMA_FLD_BIN.length())) Chris@49: { Chris@49: return load_arma_binary(x, f, err_msg); Chris@49: } Chris@49: else Chris@49: if(P6 == header.substr(0, P6.length())) Chris@49: { Chris@49: return load_ppm_binary(x, f, err_msg); Chris@49: } Chris@49: else Chris@49: { Chris@49: err_msg = "unsupported header in "; Chris@49: return false; Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: // Chris@49: // handling of PPM images by cubes Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_ppm_binary(Cube& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::fstream f; Chris@49: f.open(name.c_str(), std::fstream::in | std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_ppm_binary(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_ppm_binary(Cube& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: bool load_okay = true; Chris@49: Chris@49: std::string f_header; Chris@49: f >> f_header; Chris@49: Chris@49: if(f_header == "P6") Chris@49: { Chris@49: uword f_n_rows = 0; Chris@49: uword f_n_cols = 0; Chris@49: int f_maxval = 0; Chris@49: Chris@49: diskio::pnm_skip_comments(f); Chris@49: Chris@49: f >> f_n_cols; Chris@49: diskio::pnm_skip_comments(f); Chris@49: Chris@49: f >> f_n_rows; Chris@49: diskio::pnm_skip_comments(f); Chris@49: Chris@49: f >> f_maxval; Chris@49: f.get(); Chris@49: Chris@49: if( (f_maxval > 0) || (f_maxval <= 65535) ) Chris@49: { Chris@49: x.set_size(f_n_rows, f_n_cols, 3); Chris@49: Chris@49: if(f_maxval <= 255) Chris@49: { Chris@49: const uword n_elem = 3*f_n_cols*f_n_rows; Chris@49: podarray tmp(n_elem); Chris@49: Chris@49: f.read( reinterpret_cast(tmp.memptr()), std::streamsize(n_elem) ); Chris@49: Chris@49: uword i = 0; Chris@49: Chris@49: //cout << "f_n_cols = " << f_n_cols << endl; Chris@49: //cout << "f_n_rows = " << f_n_rows << endl; Chris@49: Chris@49: Chris@49: for(uword row=0; row < f_n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < f_n_cols; ++col) Chris@49: { Chris@49: x.at(row,col,0) = eT(tmp[i+0]); Chris@49: x.at(row,col,1) = eT(tmp[i+1]); Chris@49: x.at(row,col,2) = eT(tmp[i+2]); Chris@49: i+=3; Chris@49: } Chris@49: Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: const uword n_elem = 3*f_n_cols*f_n_rows; Chris@49: podarray tmp(n_elem); Chris@49: Chris@49: f.read( reinterpret_cast(tmp.memptr()), std::streamsize(2*n_elem) ); Chris@49: Chris@49: uword i = 0; Chris@49: Chris@49: for(uword row=0; row < f_n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < f_n_cols; ++col) Chris@49: { Chris@49: x.at(row,col,0) = eT(tmp[i+0]); Chris@49: x.at(row,col,1) = eT(tmp[i+1]); Chris@49: x.at(row,col,2) = eT(tmp[i+2]); Chris@49: i+=3; Chris@49: } Chris@49: Chris@49: } Chris@49: Chris@49: } Chris@49: Chris@49: } Chris@49: else Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "currently no code available to handle loading "; Chris@49: } Chris@49: Chris@49: if(f.good() == false) Chris@49: { Chris@49: load_okay = false; Chris@49: } Chris@49: Chris@49: } Chris@49: else Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "unsupported header in "; Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_ppm_binary(const Cube& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: Chris@49: std::ofstream f( tmp_name.c_str(), std::fstream::binary ); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_ppm_binary(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_ppm_binary(const Cube& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: arma_debug_check( (x.n_slices != 3), "diskio::save_ppm_binary(): given cube must have exactly 3 slices" ); Chris@49: Chris@49: const uword n_elem = 3 * x.n_rows * x.n_cols; Chris@49: podarray tmp(n_elem); Chris@49: Chris@49: uword i = 0; Chris@49: for(uword row=0; row < x.n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < x.n_cols; ++col) Chris@49: { Chris@49: tmp[i+0] = u8( access::tmp_real( x.at(row,col,0) ) ); Chris@49: tmp[i+1] = u8( access::tmp_real( x.at(row,col,1) ) ); Chris@49: tmp[i+2] = u8( access::tmp_real( x.at(row,col,2) ) ); Chris@49: Chris@49: i+=3; Chris@49: } Chris@49: } Chris@49: Chris@49: f << "P6" << '\n'; Chris@49: f << x.n_cols << '\n'; Chris@49: f << x.n_rows << '\n'; Chris@49: f << 255 << '\n'; Chris@49: Chris@49: f.write( reinterpret_cast(tmp.mem), std::streamsize(n_elem) ); Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: // Chris@49: // handling of PPM images by fields Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_ppm_binary(field& x, const std::string& name, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: std::fstream f; Chris@49: f.open(name.c_str(), std::fstream::in | std::fstream::binary); Chris@49: Chris@49: bool load_okay = f.is_open(); Chris@49: Chris@49: if(load_okay == true) Chris@49: { Chris@49: load_okay = diskio::load_ppm_binary(x, f, err_msg); Chris@49: f.close(); Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::load_ppm_binary(field& x, std::istream& f, std::string& err_msg) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: arma_type_check(( is_Mat::value == false )); Chris@49: typedef typename T1::elem_type eT; Chris@49: Chris@49: bool load_okay = true; Chris@49: Chris@49: std::string f_header; Chris@49: f >> f_header; Chris@49: Chris@49: if(f_header == "P6") Chris@49: { Chris@49: uword f_n_rows = 0; Chris@49: uword f_n_cols = 0; Chris@49: int f_maxval = 0; Chris@49: Chris@49: diskio::pnm_skip_comments(f); Chris@49: Chris@49: f >> f_n_cols; Chris@49: diskio::pnm_skip_comments(f); Chris@49: Chris@49: f >> f_n_rows; Chris@49: diskio::pnm_skip_comments(f); Chris@49: Chris@49: f >> f_maxval; Chris@49: f.get(); Chris@49: Chris@49: if( (f_maxval > 0) || (f_maxval <= 65535) ) Chris@49: { Chris@49: x.set_size(3); Chris@49: Mat& R = x(0); Chris@49: Mat& G = x(1); Chris@49: Mat& B = x(2); Chris@49: Chris@49: R.set_size(f_n_rows,f_n_cols); Chris@49: G.set_size(f_n_rows,f_n_cols); Chris@49: B.set_size(f_n_rows,f_n_cols); Chris@49: Chris@49: if(f_maxval <= 255) Chris@49: { Chris@49: const uword n_elem = 3*f_n_cols*f_n_rows; Chris@49: podarray tmp(n_elem); Chris@49: Chris@49: f.read( reinterpret_cast(tmp.memptr()), std::streamsize(n_elem) ); Chris@49: Chris@49: uword i = 0; Chris@49: Chris@49: //cout << "f_n_cols = " << f_n_cols << endl; Chris@49: //cout << "f_n_rows = " << f_n_rows << endl; Chris@49: Chris@49: Chris@49: for(uword row=0; row < f_n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < f_n_cols; ++col) Chris@49: { Chris@49: R.at(row,col) = eT(tmp[i+0]); Chris@49: G.at(row,col) = eT(tmp[i+1]); Chris@49: B.at(row,col) = eT(tmp[i+2]); Chris@49: i+=3; Chris@49: } Chris@49: Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: const uword n_elem = 3*f_n_cols*f_n_rows; Chris@49: podarray tmp(n_elem); Chris@49: Chris@49: f.read( reinterpret_cast(tmp.memptr()), std::streamsize(2*n_elem) ); Chris@49: Chris@49: uword i = 0; Chris@49: Chris@49: for(uword row=0; row < f_n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < f_n_cols; ++col) Chris@49: { Chris@49: R.at(row,col) = eT(tmp[i+0]); Chris@49: G.at(row,col) = eT(tmp[i+1]); Chris@49: B.at(row,col) = eT(tmp[i+2]); Chris@49: i+=3; Chris@49: } Chris@49: Chris@49: } Chris@49: Chris@49: } Chris@49: Chris@49: } Chris@49: else Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "currently no code available to handle loading "; Chris@49: } Chris@49: Chris@49: if(f.good() == false) Chris@49: { Chris@49: load_okay = false; Chris@49: } Chris@49: Chris@49: } Chris@49: else Chris@49: { Chris@49: load_okay = false; Chris@49: err_msg = "unsupported header in "; Chris@49: } Chris@49: Chris@49: return load_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_ppm_binary(const field& x, const std::string& final_name) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const std::string tmp_name = diskio::gen_tmp_name(final_name); Chris@49: std::ofstream f( tmp_name.c_str(), std::fstream::binary ); Chris@49: Chris@49: bool save_okay = f.is_open(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::save_ppm_binary(x, f); Chris@49: Chris@49: f.flush(); Chris@49: f.close(); Chris@49: Chris@49: if(save_okay == true) Chris@49: { Chris@49: save_okay = diskio::safe_rename(tmp_name, final_name); Chris@49: } Chris@49: } Chris@49: Chris@49: return save_okay; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: bool Chris@49: diskio::save_ppm_binary(const field& x, std::ostream& f) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: arma_type_check(( is_Mat::value == false )); Chris@49: Chris@49: typedef typename T1::elem_type eT; Chris@49: Chris@49: arma_debug_check( (x.n_elem != 3), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" ); Chris@49: Chris@49: bool same_size = true; Chris@49: for(uword i=1; i<3; ++i) Chris@49: { Chris@49: if( (x(0).n_rows != x(i).n_rows) || (x(0).n_cols != x(i).n_cols) ) Chris@49: { Chris@49: same_size = false; Chris@49: break; Chris@49: } Chris@49: } Chris@49: Chris@49: arma_debug_check( (same_size != true), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" ); Chris@49: Chris@49: const Mat& R = x(0); Chris@49: const Mat& G = x(1); Chris@49: const Mat& B = x(2); Chris@49: Chris@49: f << "P6" << '\n'; Chris@49: f << R.n_cols << '\n'; Chris@49: f << R.n_rows << '\n'; Chris@49: f << 255 << '\n'; Chris@49: Chris@49: const uword n_elem = 3 * R.n_rows * R.n_cols; Chris@49: podarray tmp(n_elem); Chris@49: Chris@49: uword i = 0; Chris@49: for(uword row=0; row < R.n_rows; ++row) Chris@49: { Chris@49: for(uword col=0; col < R.n_cols; ++col) Chris@49: { Chris@49: tmp[i+0] = u8( access::tmp_real( R.at(row,col) ) ); Chris@49: tmp[i+1] = u8( access::tmp_real( G.at(row,col) ) ); Chris@49: tmp[i+2] = u8( access::tmp_real( B.at(row,col) ) ); Chris@49: Chris@49: i+=3; Chris@49: } Chris@49: } Chris@49: Chris@49: f.write( reinterpret_cast(tmp.mem), std::streamsize(n_elem) ); Chris@49: Chris@49: return f.good(); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! @} Chris@49: