C++自定义file头文件

#ifndef __SEAL_FILEPOOL_H__
#define __SEAL_FILEPOOL_H__

#include "error.h"
#include "hash.h"
#include "macro.h"
#include "path.h"
#include "threads.h"

#include <string>

#include <cstdio>


namespace sea {

namespace posix {
#include <sys/stat.h>
}


class file_pool {
private:
	static constexpr int FGR = 1;
	static constexpr int FGW = 2;
	static constexpr int FGA = 4;
	static constexpr int FGP = 8;
	static constexpr int FGB = 16;

	struct opened {
		int flag;
		FILE *file;
		int rc;
	};
	sea::hash_map<size_t, opened> _opened;

	spin_lock _lock;

	file_pool() = default;
	~file_pool() noexcept {
		for (auto &p : _opened) {
			fclose(p.second.file);
		}
	}

	seal_macro_non_copy(file_pool)

	static file_pool &instance() {
		static file_pool fp;
		return fp;
	}

	FILE *open_impl(const char *p, const char *m) {
		if ( !p || *p == '\0' || strcmp(p, "null") == 0 ) {
			p = "/dev/null";
		} else if ( strcmp(p, "stdin") == 0 ) {
			return stdin;
		} else if ( strcmp(p, "stdout") == 0 ) {
			return stdout;
		} else if ( strcmp(p, "stderr") == 0 ) {
			return stderr;
		}

		int fg = 0;
		fg |= strchr(m, 'r') ? FGR : 0;
		fg |= strchr(m, 'w') ? FGW : 0;
		fg |= strchr(m, 'a') ? FGA : 0;
		fg |= strchr(m, '+') ? FGP : 0;
		fg |= strchr(m, 'b') ? FGB : 0;

		if ( strcmp(p, "-") == 0 ) {
			if ( (fg & (FGW | FGA | FGP)) == 0 ) {
				return stdin;
			} else if ( (fg & (FGR | FGP)) == 0 ) {
				return stdout;
			}
		}

		using namespace posix;
		struct stat sb;
		int rt = stat(p, &sb);
		std::lock_guard<spin_lock> lg(_lock);
		if ( rt != 0 || _opened.count(sb.st_ino) == 0 ) {
			FILE *f = fopen(p, m);
			if ( f == nullptr ) {
				raise(cannot_open(p, m));
			} else {
				size_t n = inode(f);
				_opened.insert({n, opened{fg, f, 1}});
			}
			return f;
		} else {
			auto i = _opened.find(sb.st_ino);
			if ( i->second.flag == fg ) {
				++i->second.rc;
				return i->second.file;
			}
			raise(cannot_open(p, m));
			return nullptr;
		}
	}

	void close_impl(FILE *f) {
		if ( f == stdin || f == stdout || f == stderr ) {
			return;
		}
		size_t n = inode(f);
		std::lock_guard<spin_lock> lg(_lock);
		auto i = _opened.find(n);
		if ( i != _opened.end() && --i->second.rc == 0 ) {
			fclose(i->second.file);
			_opened.erase(i);
		}
	}

	size_t inode(FILE *f) {
		using namespace posix;
		struct stat sb;
		fstat(fileno(f), &sb);
		return sb.st_ino;
	}

	static file_error cannot_open(const char *p, const char *m) {
		char s[1024];
		snprintf(s, 1024, "cannot open file \"%s\" with flag \"%s\"\n", p, m);
		return file_error(s);
	}

public:
	static FILE *open(const char *p, const char *m) {
		return instance().open_impl(p, m);
	}

	static FILE *open(const std::string &p, const std::string &m) {
		return open(p.data(), m.data());
	}

	static void close(FILE *f) {
		instance().close_impl(f);
	}

};

}

#endif // __SEAL_FILEPOOL_H__

/src/sealib/filepool.h文件描述了程序对于文件处理的一些函数,如open(),close(),基本上实现了文件的所有状态判断与操作。其中static constexpr定义了一些静态常量数据。程序中运用了一些线程的知识。The design of lock_guard is quite straight-forward. Basically, lock_guard requires the resource it can lock to have two methods, lock() and unlock(), once your resource class has these two methods, it can be used with lock_guard. lock_guard will call lock() in constructor and call unlock() in destructor. 

其中文件file的定义位于/usr/include/stdio.h这个头文件中。

/* The opaque type of streams.  This is the definition used elsewhere.  */
typedef struct _IO_FILE FILE;
__END_NAMESPACE_STD
#if defined __USE_LARGEFILE64 || defined __USE_SVID || defined __USE_POSIX \
    || defined __USE_BSD || defined __USE_ISOC99 || defined __USE_XOPEN \
    || defined __USE_POSIX2
__USING_NAMESPACE_STD(FILE)
#endif
相关文章
相关标签/搜索