You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

455 lines
15 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: platformstl/filesystem/file_lines.hpp
  3. *
  4. * Purpose: Platform header for the file_lines components.
  5. *
  6. * Created: 25th October 2007
  7. * Updated: 10th September 2010
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2007-2010, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are
  16. * met:
  17. *
  18. * - Redistributions of source code must retain the above copyright notice,
  19. * this list of conditions and the following disclaimer.
  20. * - Redistributions in binary form must reproduce the above copyright
  21. * notice, this list of conditions and the following disclaimer in the
  22. * documentation and/or other materials provided with the distribution.
  23. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the
  24. * names of any contributors may be used to endorse or promote products
  25. * derived from this software without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  31. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. * ////////////////////////////////////////////////////////////////////// */
  40. #ifndef PLATFORMSTL_INCL_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES
  41. #define PLATFORMSTL_INCL_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES
  42. /* File version */
  43. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  44. # define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES_MAJOR 1
  45. # define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES_MINOR 4
  46. # define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES_REVISION 9
  47. # define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES_EDIT 27
  48. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  49. /** \file platformstl/filesystem/file_lines.hpp
  50. *
  51. * \brief [C++ only] Definition of the platformstl::file_lines type
  52. * (\ref group__library__filesystem "File System" Library).
  53. *
  54. * When compiling on UNIX platforms, the platformstl::file_lines
  55. * type resolves to the unixstl::file_lines class. On Windows
  56. * platforms it resolves to the winstl::file_lines class. It is
  57. * not defined for other platforms.
  58. */
  59. /* /////////////////////////////////////////////////////////////////////////
  60. * Includes
  61. */
  62. #ifndef PLATFORMSTL_INCL_PLATFORMSTL_HPP_PLATFORMSTL
  63. # include <platformstl/platformstl.hpp>
  64. #endif /* !PLATFORMSTL_INCL_PLATFORMSTL_HPP_PLATFORMSTL */
  65. #ifndef PLATFORMSTL_INCL_PLATFORMSTL_FILESYSTEM_HPP_MEMORY_MAPPED_FILE
  66. # include <platformstl/filesystem/memory_mapped_file.hpp>
  67. #endif /* !PLATFORMSTL_INCL_PLATFORMSTL_FILESYSTEM_HPP_MEMORY_MAPPED_FILE */
  68. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  69. # ifndef STLSOFT_INCL_STLSOFT_CONVERSION_HPP_TRUNCATION_CAST
  70. # include <stlsoft/conversion/truncation_cast.hpp>
  71. # endif /* !STLSOFT_INCL_STLSOFT_CONVERSION_HPP_TRUNCATION_CAST */
  72. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  73. #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_STRING_H_FWD
  74. # include <stlsoft/shims/access/string/fwd.h>
  75. #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_STRING_H_FWD */
  76. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TOKENISER
  77. # include <stlsoft/string/string_tokeniser.hpp>
  78. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TOKENISER */
  79. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_VIEW
  80. # include <stlsoft/string/string_view.hpp>
  81. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_VIEW */
  82. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING
  83. # include <stlsoft/string/simple_string.hpp>
  84. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING */
  85. #ifndef STLSOFT_INCL_ALGORITHM
  86. # define STLSOFT_INCL_ALGORITHM
  87. # include <algorithm>
  88. #endif /* !STLSOFT_INCL_ALGORITHM */
  89. #ifndef STLSOFT_INCL_UTILITY
  90. # define STLSOFT_INCL_UTILITY
  91. # include <utility>
  92. #endif /* !STLSOFT_INCL_UTILITY */
  93. #ifndef STLSOFT_INCL_VECTOR
  94. # define STLSOFT_INCL_VECTOR
  95. # include <vector>
  96. #endif /* !STLSOFT_INCL_VECTOR */
  97. #ifdef STLSOFT_UNITTEST
  98. # include <platformstl/filesystem/file_path_buffer.hpp>
  99. #endif /* STLSOFT_UNITTEST */
  100. /* /////////////////////////////////////////////////////////////////////////
  101. * Namespace
  102. */
  103. #if defined(_STLSOFT_NO_NAMESPACE) || \
  104. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  105. /* There is no stlsoft namespace, so must define ::platformstl */
  106. namespace platformstl
  107. {
  108. #else
  109. /* Define stlsoft::platformstl_project */
  110. namespace stlsoft
  111. {
  112. namespace platformstl_project
  113. {
  114. #endif /* _STLSOFT_NO_NAMESPACE */
  115. /* /////////////////////////////////////////////////////////////////////////
  116. * Classes
  117. */
  118. /** Maps a text file's contents and presents them as a vector of lines
  119. */
  120. template< ss_typename_param_k C
  121. , ss_typename_param_k V = stlsoft::basic_string_view<C>
  122. , ss_typename_param_k B = stlsoft::basic_simple_string<C>
  123. >
  124. class basic_file_lines
  125. {
  126. /// \name Member Types
  127. /// @{
  128. public:
  129. typedef basic_file_lines<C, V, B> class_type;
  130. typedef C char_type;
  131. private:
  132. typedef V value_string_type_;
  133. typedef B base_string_type_;
  134. typedef std::vector<V> strings_type_;
  135. typedef memory_mapped_file mmf_type_;
  136. public:
  137. typedef ss_typename_type_k strings_type_::value_type value_type;
  138. typedef ss_typename_type_k strings_type_::size_type size_type;
  139. typedef ss_typename_type_k strings_type_::const_iterator const_iterator;
  140. typedef ss_typename_type_k strings_type_::const_reference const_reference;
  141. typedef ss_bool_t bool_type;
  142. /// @}
  143. /// \name Construction
  144. /// @{
  145. public:
  146. template <ss_typename_param_k S>
  147. ss_explicit_k basic_file_lines(S const& path)
  148. : m_mmf(NULL) /* NOTE: can't initialise m_mmf here, as Borland causes the MMF ctor to fail with Access Denied. Go figure! */
  149. , m_contents()
  150. , m_strings()
  151. {
  152. create_(new mmf_type_(stlsoft_ns_qual(c_str_ptr)(path))); // See comment above for why we initialise intra-body
  153. }
  154. private:
  155. void create_(mmf_type_* pmmf)
  156. {
  157. #ifdef STLSOFT_CF_THROW_BAD_ALLOC
  158. STLSOFT_ASSERT(NULL != pmmf);
  159. #else /* ? STLSOFT_CF_THROW_BAD_ALLOC */
  160. if(NULL != pmmf)
  161. #endif /* STLSOFT_CF_THROW_BAD_ALLOC */
  162. {
  163. stlsoft_ns_qual_std(auto_ptr)<mmf_type_> scoper(pmmf);
  164. mmf_type_ const& mmf = *pmmf;
  165. char_type const* const base = static_cast<char_type const*>(mmf.memory());
  166. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  167. size_type const cch = stlsoft_ns_qual(truncation_cast)<size_type>(mmf.size() / sizeof(char_type));
  168. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  169. size_type const cch = static_cast<size_type>(mmf.size() / sizeof(char_type));
  170. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  171. m_strings.reserve(cch / 40);
  172. #if defined(PLATFORMSTL_OS_IS_WINDOWS) || \
  173. ( defined(PLATFORMSTL_OS_IS_UNIX) && \
  174. defined(_WIN32))
  175. typedef stlsoft::string_tokeniser<
  176. value_type
  177. , value_type
  178. , stlsoft::skip_blank_tokens<false>
  179. , value_type
  180. > tokeniser_t_;
  181. static const char_type sep[] = { '\r', '\n', '\0' };
  182. #elif defined(PLATFORMSTL_OS_IS_UNIX)
  183. typedef stlsoft::string_tokeniser<
  184. value_type
  185. , char
  186. , stlsoft::skip_blank_tokens<false>
  187. , value_type
  188. > tokeniser_t_;
  189. static const char_type sep = '\n';
  190. #else /* ? OS */
  191. # error Platform not discriminated
  192. #endif /* OS */
  193. m_contents = base_string_type_(base, cch);
  194. tokeniser_t_ lines(m_contents.data(), m_contents.size(), sep);
  195. std::copy(lines.begin(), lines.end(), std::back_inserter(m_strings));
  196. // Now determine whether we can discard the underlying mapping. This
  197. // is ok if:
  198. // - there are no lines, or
  199. // - the string type copies. This is determined by checking whether
  200. // the first non-empty string's contents point within the mapping.
  201. bool canDiscardMapping = false;
  202. if(!canDiscardMapping)
  203. {
  204. canDiscardMapping = m_strings.empty();
  205. }
  206. if(!canDiscardMapping)
  207. {
  208. { for(ss_typename_type_k strings_type_::const_iterator i = m_strings.begin(); i != m_strings.end(); ++i)
  209. {
  210. if(0u != (*i).size())
  211. {
  212. void const* base = mmf.memory();
  213. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  214. void const* end = ptr_byte_offset(base, stlsoft_ns_qual(truncation_cast)<ss_ptrdiff_t>(mmf.size()));
  215. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  216. void const* end = ptr_byte_offset(base, static_cast<ss_ptrdiff_t>(mmf.size()));
  217. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  218. void const* p = (*i).data();
  219. canDiscardMapping = p < base || p >= end;
  220. break;
  221. }
  222. }}
  223. }
  224. if(!canDiscardMapping)
  225. {
  226. m_mmf = scoper.release();
  227. }
  228. }
  229. }
  230. public:
  231. ~basic_file_lines() stlsoft_throw_0()
  232. {
  233. delete m_mmf;
  234. }
  235. /// @}
  236. /// \name Accessors
  237. /// @{
  238. public:
  239. /// Returns the number of lines in the file
  240. size_type size() const
  241. {
  242. return m_strings.size();
  243. }
  244. /// Indicates whethere there are any lines in the file
  245. bool_type empty() const
  246. {
  247. return 0u == size();
  248. }
  249. /// Returns a non-mutable (const) reference to the line at \c index
  250. ///
  251. /// \note The behaviour is undefined if index >= size()
  252. const_reference operator [](size_type index) const
  253. {
  254. STLSOFT_MESSAGE_ASSERT("index out of range", index < size());
  255. return m_strings[index];
  256. }
  257. /// Begins the iteration
  258. ///
  259. /// \return An iterator representing the start of the sequence
  260. const_iterator begin() const
  261. {
  262. return m_strings.begin();
  263. }
  264. /// Ends the iteration
  265. ///
  266. /// \return An iterator representing the end of the sequence
  267. const_iterator end() const
  268. {
  269. return m_strings.end();
  270. }
  271. /// @}
  272. /// \name Comparison
  273. /// @{
  274. public:
  275. #if !defined(STLSOFT_COMPILER_IS_DMC)
  276. template< ss_typename_param_k V2
  277. , ss_typename_param_k B2
  278. >
  279. bool_type equal(basic_file_lines<char_type, V2, B2> const& rhs) const
  280. #else /* ? compiler */
  281. bool_type equal(class_type const& rhs) const
  282. #endif /* compiler */
  283. {
  284. if(size() != rhs.size())
  285. {
  286. return false;
  287. }
  288. return stlsoft_ns_qual_std(equal)(begin(), end(), rhs.begin());
  289. }
  290. /// @}
  291. /// \name Member Variables
  292. /// @{
  293. private:
  294. mmf_type_* m_mmf;
  295. base_string_type_ m_contents;
  296. strings_type_ m_strings;
  297. /// @}
  298. /// \name Not to be implemented
  299. /// @{
  300. private:
  301. basic_file_lines(class_type const& );
  302. class_type& operator =(class_type const& );
  303. // Prevents the conversion constructor from being invoked on an instance
  304. // of a different specialisation
  305. template<
  306. ss_typename_param_k C2
  307. , ss_typename_param_k V2
  308. , ss_typename_param_k B2
  309. >
  310. basic_file_lines(basic_file_lines<C2, V2, B2> const& );
  311. /// @}
  312. };
  313. /* /////////////////////////////////////////////////////////////////////////
  314. * Typedefs for commonly encountered types
  315. */
  316. /** \brief Specialisation of the basic_file_lines template for the ANSI character type \c char
  317. *
  318. * \ingroup group__library__filesystem
  319. */
  320. typedef basic_file_lines<ss_char_a_t> file_lines_a;
  321. /** \brief Specialisation of the basic_file_lines template for the Unicode character type \c wchar_t
  322. *
  323. * \ingroup group__library__filesystem
  324. */
  325. typedef basic_file_lines<ss_char_w_t> file_lines_w;
  326. #ifdef TCHAR
  327. /** \brief Specialisation of the basic_file_lines template for the Win32 character type \c TCHAR
  328. *
  329. * \ingroup group__library__filesystem
  330. */
  331. typedef basic_file_lines<TCHAR> file_lines;
  332. #else /* ? TCHAR */
  333. typedef file_lines_a file_lines;
  334. #endif /* TCHAR */
  335. /** \brief Alias for platformstl::file_lines_w;
  336. *
  337. * \ingroup group__library__filesystem
  338. */
  339. typedef file_lines_w wfile_lines;
  340. /* /////////////////////////////////////////////////////////////////////////
  341. * Operators
  342. */
  343. #if !defined(STLSOFT_COMPILER_IS_DMC)
  344. template< ss_typename_param_k C
  345. , ss_typename_param_k V1
  346. , ss_typename_param_k B1
  347. , ss_typename_param_k V2
  348. , ss_typename_param_k B2
  349. >
  350. inline ss_typename_type_ret_k basic_file_lines<C, V1, B1>::bool_type operator ==(basic_file_lines<C, V1, B1> const& lhs, basic_file_lines<C, V2, B2> const& rhs)
  351. #else /* ? compiler */
  352. template< ss_typename_param_k C
  353. , ss_typename_param_k V
  354. , ss_typename_param_k B
  355. >
  356. inline ss_typename_type_ret_k basic_file_lines<C, V, B>::bool_type operator ==(basic_file_lines<C, V, B> const& lhs, basic_file_lines<C, V, B> const& rhs)
  357. #endif /* compiler */
  358. {
  359. return lhs.equal(rhs);
  360. }
  361. #if !defined(STLSOFT_COMPILER_IS_DMC)
  362. template< ss_typename_param_k C
  363. , ss_typename_param_k V1
  364. , ss_typename_param_k B1
  365. , ss_typename_param_k V2
  366. , ss_typename_param_k B2
  367. >
  368. inline ss_typename_type_ret_k basic_file_lines<C, V1, B1>::bool_type operator !=(basic_file_lines<C, V1, B1> const& lhs, basic_file_lines<C, V2, B2> const& rhs)
  369. #else /* ? compiler */
  370. template< ss_typename_param_k C
  371. , ss_typename_param_k V
  372. , ss_typename_param_k B
  373. >
  374. inline ss_typename_type_ret_k basic_file_lines<C, V, B>::bool_type operator !=(basic_file_lines<C, V, B> const& lhs, basic_file_lines<C, V, B> const& rhs)
  375. #endif /* compiler */
  376. {
  377. return !lhs.equal(rhs);
  378. }
  379. /* ////////////////////////////////////////////////////////////////////////
  380. * Unit-testing
  381. */
  382. #ifdef STLSOFT_UNITTEST
  383. # include "./unittest/file_lines_unittest_.h"
  384. #endif /* STLSOFT_UNITTEST */
  385. /* ////////////////////////////////////////////////////////////////////// */
  386. #if defined(_STLSOFT_NO_NAMESPACE) || \
  387. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  388. } // namespace platformstl
  389. #else
  390. } // namespace platformstl_project
  391. } // namespace stlsoft
  392. #endif /* _STLSOFT_NO_NAMESPACE */
  393. /* ////////////////////////////////////////////////////////////////////// */
  394. #endif /* !PLATFORMSTL_INCL_PLATFORMSTL_FILESYSTEM_HPP_FILE_LINES */
  395. /* ///////////////////////////// end of file //////////////////////////// */