1.OC&Swift测试工程配置
I.在测试工程中测试主工程中代码,直接引入头文件进行调用
II.编写Swift测试用例
创建时点击Create Bridging Header,此时依然无法使用ViewController类中的方法
在主工程中创建swift工程,让系统生成桥接文件,在桥接文件中引入“ViewController.h”,此时还需在需要使用OC文件的地方引入主Module才能使用ViewController
Swift测试文件使用OC代码的时候
A.主工程Bridge文件导出相关的头文件
B.Swift测试文件引入主工程Module
TestAppTests-Bridging-Header.h是将测试工程中的OC文件给测试工程中的swift使用
TestApp-Bridging-Header.h是将主工程中的OC文件给其他swift代码使用
在主工程swift文件中新建两个module,在测试工程中如何使用呢?
swift没有权限控制符的时候,默认为不开放,此时用@testable import导入主工程公开权限,只是针对测试工程使用
若swift类使用public、open修饰,则import TestApp能访问到
若没有修饰或internal修饰,则需要使用@testable import TestApp
若在OC中使用swift model,并不能直接使用,需要引入系统帮我们默认生成的头文件,头文件以当前App名称开头-Swift.h
同理,若要在测试工程中使用swift相关的代码,需要引入TestApp-Swift.h头文件,然而TestApp和TestAppTests属于两个target,两个不同的项目,TestApp系统默认生成的TestApp-Swift.h,我们是直接访问不到的,需要在header search path中指明路径
TestApp-Swift.h在product目录下,show in finder
Xcode会自动生成一个环境变量$CONFIGURATION_TEMP_DIR,
指向如下目录
TestApp-Swift.h所在的路径为$CONFIGURATION_TEMP_DIR/TestApp.build/DerivedSources,放入TestAppTests工程的header search paths中
递归和不递归的区别是,递归情况下,会在给的
路径下面的子文件夹中去寻找,若非递归状态下
不会在子目录下面去找,相当于需要给绝对路径
递归状态下,配置绝对路径
2.header search path底层是-I,接收两个参数,头文件的目录,指定hmap文件
hmap:key-value,为什么-I可以通过hmap解析到头文件所在的目录,这是美团这篇文章的重点一款可以让大型iOS工程编译速度提升50%的工具
如何通过hmap加快编译速度?
hmap是一个容器,包裹着头文件所在的目录,通过xcode去查找文件的时候更快速
hmap文件如何生成?底层结构是什么样的?
查看.m文件的编译,发现在编译期底层通过-I参数链接了-I/Users/cloud/Library/Developer/Xcode/DerivedData/TestApp-azujxtfyspnygtekfcgtbfaeptix/Build/Intermediates.noindex/TestApp.build/Debug-iphonesimulator/TestApp.build/TestApp-all-target-headers.hmap
来到这个目录,发现有很多hmap文件
通过cat查看.hmap中的内容,怎么理解.hmap底层到底是什么样的数据结构体呢?借助llvm工程查看.hmap的结构,hmap文件由HampHeader和HmapBucket,若target中包含3个头文件,则会有3个HmapBucket,Bucket的数量与头文件的数量相等,
通过读取Hmapheader,知道当前二进制里面有多少个Bucket,Bucket表示当前的hmap里面保存了多少个头文件的路径,通过Bucket,底下保存了字符串,Bucket中有偏移量,可以根据偏移量计算出保存字符串的位置,从而读取出头文件的路径
前半部分是配置文件,后半部分存储真正的信息
怎么将文件读取成结构体,再读取出头文件的字符串呢?
在llvm中的LexTests target中我们发现了结构体HMapBucket和HMapHeader,同时发现将.hmap解析成HMapBucket和HMapHeader的源代码
通过C函数读取hmap文件,提取其中的HmapHeader和HmapBucket,将二进制转化为结构体,通过打印HMapBucket中的Key、Prefix、Suffix
struct HMapBucket {
uint32_t Key; // Offset (into strings) of key.
uint32_t Prefix; // Offset (into strings) of value prefix.
uint32_t Suffix; // Offset (into strings) of value suffix.
};
将前文生成的TestApp-project-headers.hmap拖入到读取.hmap文件的根目录下
Xcode配置的读取.hmap文件路径中不能有空格
将.hmap文件的路径传入main函数中,通过C语言和结构体内存平移原则,先读取HmapHeader,再读取HmapBucket
HMapHeader -> 指明了有多少个Bucket
每一个Bucket代表了一个头文件string_table位置
字符串读取出来:HMapBucket紧跟着HMapHeader
Bucket首地址:string_table首地址 = HMapHeader大小 + num *HMapBucket
void
dump(const char *path)
{
// c来写
// OCSwift
// hmap文件路径
int fd = open(path, O_RDONLY|O_CLOEXEC);
if (fd < 0) {
warn(/*EX_NOINPUT,*/ "%s: cannot open", path);
return;
}
struct HMapHeader header;
// 二进制数据
// sizeof(HMapHeader)
// header -> Bucket-> 读取Bucket表示的头文件路径
ssize_t nread = read(fd, &header, sizeof(header));
if (nread < 0) {
warn(/*EX_IOERR,*/ "%s: failed to read header", path);
(void)close(fd);
return;
} else if ((size_t)nread < sizeof(header)) {
warn(
/*EX_DATAERR,*/
"%s: short read: expected %zu bytes, read only %zd",
path, sizeof(header), nread);
(void)close(fd);
return;
}
bool is_swapped = false;
uint32_t (*swap)(uint32_t) = nop_swap;
if (header.Magic == HMAP_HeaderMagicNumber
&& header.Version == HMAP_HeaderVersion) {
is_swapped = false;
} else if (header.Magic == HMAP_SwappedMagic
&& header.Version == HMAP_SwappedVersion) {
is_swapped = true;
swap = actually_swap;
} else {
warn(/*EX_DATAERR,*/ "header lacks HMAP magic");
(void)close(fd);
return;
}
// 8 数据对齐
const uint32_t bucket_count = swap(header.NumBuckets);
printf("Header map: %s\n"
"\tHash bucket count: %" PRIu32 "\n"
"\tString table entry count: %" PRIu32 "\n"
"\tMax value length: %" PRIu32 " bytes\n",
path,
bucket_count,
swap(header.NumEntries),
swap(header.MaxValueLength));
struct stat stat;
int stat_err = fstat(fd, &stat);
if (stat_err) {
warn("%s: fstat failed; cannot dump buckets", path);
(void)close(fd);
return;
}
off_t hmap_length = stat.st_size;
const void *hmap = mmap(0, hmap_length, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0 /*offset*/);
(void)close(fd);
if (MAP_FAILED == hmap) {
warn("%s: failed to mmap; cannot dump buckets", path);
return;
}
const char *raw = (const char *)hmap;
// mach header -》指明了有多少个load commands
// HMapHeader -》指明了有多少个Bucket
// 每一个Bucket代表了一个头文件string_table位置
// HMapBucket紧跟着HMapHeader
// HMapBucket
//
// 字符串读取出来
// Bucket首地址
// string_table首地址 = HMapHeader大小 + num *HMapBucket
const struct HMapBucket *const buckets = (const struct HMapBucket *const)(raw
+ sizeof(struct HMapHeader));
const char *const string_table = (raw
+ sizeof(struct HMapHeader)
+ bucket_count*sizeof(struct HMapBucket));
// 2
for (uint32_t i = 0; i < bucket_count; ++i) {
const struct HMapBucket *const bucket = &(buckets[i]);
if (swap(bucket->Key) == HMAP_EmptyBucketKey) { continue; }
//
// LLVM is careful to sanity-check bucket-count and strlen,
// but we're just going to assume they're all NUL-terminated
// and not maliciously crafted input files.
//
// This is naive, but this is also not exactly "production" code.
// string_table 位置
// 首地址 + 位置
const char *key = string_table + swap(bucket->Key);
const char *prefix = string_table + swap(bucket->Prefix);
const char *suffix = string_table + swap(bucket->Suffix);
printf("\t- Bucket %" PRIu32 ": "
"Key %s -> Prefix %s, Suffix %s\n",
i,
key, prefix, suffix);
}
}
/**
// 主题
Key LGTestApp-Bridging-Header.h
//头文件的前半部分
Prefix /Users/ws/Desktop/VIP课程/第十六节课、单元测试与UI测试/上课代码/01-OC&Swift测试工程配置/LGTestApp/LGTestApp/
//头文件的后半部分
Suffix LGTestApp-Bridging-Header.h
// hmap 对应 按照规则存储一堆的头文件
*/
uint32_t
nop_swap(uint32_t u)
{
return u;
}
uint32_t
actually_swap(uint32_t u)
{
uint32_t n = (
((u & 0xFF) << 24)
| ((u & 0xFF00) << 8)
| ((u & 0xFF0000) >> 8)
| ((u & 0xFF000000) >> 24)
);
return n;
}
int
main(int argc, const char *argv[])
{
assert(actually_swap(HMAP_HeaderMagicNumber) == HMAP_SwappedMagic
&& "failed to properly swap things :(");
// header map 路径
if (argc < 2) {
fprintf(
stderr,
"usage: %s HMAP_FILE [HMAP_FILE...]\n\n"
"Dump clang headermap (.hmap file) contents.\n\n"
"See: https://github.com/llvm-mirror/clang/blob/release_40/include/clang/Lex/HeaderMapTypes.h\n"
"and related files\n",
getprogname());
return EX_USAGE;
}
for (int i = 1; i < argc; ++i) {
//导出 header map
dump(argv[i]);
putchar('\n');
}
return EXIT_SUCCESS;
}
读取出来头文件结果,包含工程中的5个头文件,每个bucket由key、prefix、suffix组成,分别为工程中的TestApp-Bridging-Header.h,ViewController.h,AppDelegate.h,SceneDelegate.h,TestAppTests-Bridging-Header.h,并不说一定是8个bucket,存在数据对齐规则
key:表示主题
Prefix:表示头文件的前半部分
Suffix:表示头文件的后半部分
hmap对应按照规则存储的一堆头文件
Header map: /Users/cloud/Documents/iOS/iOS强化班/LoginiOS高级强化班/第十六节课、单元测试与UI测试/上课代码/02-HeaderMap原理&读取/DumpHeaderMap/TestApp-project-headers.hmap
Hash bucket count: 8
String table entry count: 5
Max value length: 0 bytes
- Bucket 0: Key TestApp-Bridging-Header.h -> Prefix /Users/cloud/Documents/iOS/iOS强化班/Login iOS 高级强化班/第十六节课、单元测试与UI测试/TestApp/TestApp/, Suffix TestApp-Bridging-Header.h
- Bucket 1: Key ViewController.h -> Prefix /Users/cloud/Documents/iOS/iOS强化班/Login iOS 高级强化班/第十六节课、单元测试与UI测试/TestApp/TestApp/, Suffix ViewController.h
- Bucket 2: Key AppDelegate.h -> Prefix /Users/cloud/Documents/iOS/iOS强化班/Login iOS 高级强化班/第十六节课、单元测试与UI测试/TestApp/TestApp/, Suffix AppDelegate.h
- Bucket 3: Key SceneDelegate.h -> Prefix /Users/cloud/Documents/iOS/iOS强化班/Login iOS 高级强化班/第十六节课、单元测试与UI测试/TestApp/TestApp/, Suffix SceneDelegate.h
- Bucket 7: Key TestAppTests-Bridging-Header.h -> Prefix /Users/cloud/Documents/iOS/iOS强化班/Login iOS 高级强化班/第十六节课、单元测试与UI测试/TestApp/TestAppTests/, Suffix TestAppTests-Bridging-Header.h
3.美团的文章说生成的头文件为n,生成的hmap文件为n+1,1代表1个,n代表n个
-I链接头文件可以接受两种参数,第一种是接收一个路径,第二种是接收.hmap文件
两种查找头文件的方式
I.查找头文件通过目录的方式查找,如cocoapods自动生成的debug.xcconfig文件
缺点:若在多个目录里面寻找一个头文件,会比较耗时,如果能把一个文件路径提前放在一个hmap文件里面,去读取文件里面的路径会快很多,header search paths中有头文件的数量限制的
若头文件比较少,不需要用到.hmap文件,头文件越少,.hmap的作用越不明显,
头文件数量越多越明显
II.通过加载.hmap文件解析方式查找
4.通过终端直接查看.hmap文件里面的内容
A.将DumpHeaderMap的可执行文件复制到全局目录路径中,往shell配置文件中导出路径,将可执行文件路径放入~/.bashrc中,执行source ~/.bashrc,使环境变量生效
B.检验DumpHeaderMap命令是否生效,发现已经生效,此时头文件的路径均为绝对路径,在什么情况下头文件的路径会是相对路径呢?
在前文的工程中新建Headers Phase,将ViewController拖到Public目录下,Cmd + B编译后,得到新的.hmap文件,查看路径,发现ViewController.h由绝对路径变为了相对路径
将ViewController.h拖入Project目录下,此时编译生成的.hmap文件里面的ViewController.h文件才是绝对路径目录
美团文章里面,n+1中n表示私有头文件(绝对路径的可以放到一起),1表示公共头文件(公有的头文件放到一起)
5.怎么生成.hmap头文件呢?
前文在测试工程中,使用swift相关代码,需要引入TestApp-Swift.h头文件,而测试工程和主工程属于不同的target,要引入头文件,需要在header search path中指明路径,此时可以模拟生成一个.hmap文件,包含TestApp-Swift.h头文件来替换header search path中的路径
I.生成包含TestApp-Swift.h头文件的.hmap文件,将TestApp-Swift.h头文件拷贝到工程SRCROOT目录下
II.在配置工程中去插入Bucket,只配置一个TestApp-Swift.h,生成.mm文件中包含这个Bucket
III.在TestApp的测试工程TestAppTests的header search paths中指定包含TestApp-Swift.h文件的mm.hmap文件的路径,此时发现仍旧找不到TestApp-Swift.h头文件的路径,原因是.hmap中包含的.h文件要全,当前target工程中引用的其他的头文件也要写入mm.hmap中,ViewController.h和TestApp-Bridging-Header.h,均写入mm.hmap文件中
新加ViewController.h和TestApp-Bridging-Header.h,均写入mm.hmap文件中
重新运行Cmd + U 进行编译,看工程是否能找到TestApp-Swift.h头文件
此时仍然找不到TestApp-Swift.h头文件
查看当前项目TestApp中Xcode生成的TestApp-project-headers.hmap文件中包含的头文件,发现有5个头文件,继续往.mm文件中添加TestAppTests-Bridging-Header.h头文件
增加TestAppTests-Bridging-Header.h头文件后,mm.hmap中的头文件的数量变为4个,此时编译还是不通过,加大数字typedef MapFile<8, 750> FileTy;重新编译
typedef MapFile<8, 750> FileTy,控制生成多少个NumBuckets,NumBytes
此时能build success,mm.hmap文件中写入头文件管用
生成.hmap源码如下
#import <Foundation/Foundation.h>
#include <stdio.h>
#include <stdlib.h>
#include <sysexits.h>
#include <err.h>
#include <fcntl.h>
#include <stdbool.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string>
#include <malloc/malloc.h>
enum {
HMAP_HeaderMagicNumber = ('h' << 24) | ('m' << 16) | ('a' << 8) | 'p',
HMAP_HeaderVersion = 0x0001,
HMAP_EmptyBucketKey = 0,
HMAP_SwappedMagic = ('h' << 0) | ('m' << 8) | ('a' << 16) | ('p' << 24),
HMAP_SwappedVersion = 0x0100,
};
struct HMapBucket {
uint32_t Key; // Offset (into strings) of key.
uint32_t Prefix; // Offset (into strings) of value prefix.
uint32_t Suffix; // Offset (into strings) of value suffix.
};
struct HMapHeader {
uint32_t Magic; // Magic word, also indicates byte order.
uint16_t Version; // Version number -- currently 1.
uint16_t Reserved; // Reserved for future use - zero for now.
uint32_t StringsOffset; // Offset to start of string pool.
uint32_t NumEntries; // Number of entries in the string table.
uint32_t NumBuckets; // Number of buckets (always a power of 2).
uint32_t MaxValueLength; // Length of longest result path (excluding nul).
// An array of 'NumBuckets' HMapBucket objects follows this header.
// Strings follow the buckets, at StringsOffset.
};
void write();
uint32_t nop_swap(uint32_t);
uint32_t actually_swap(uint32_t);
// The header map hash function.
static inline unsigned getHash(NSString *Str) {
return Str.hash;
}
inline uint32_t ByteSwap_32(uint32_t value) {
#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
return __builtin_bswap32(value);
#elif defined(_MSC_VER) && !defined(_DEBUG)
return _byteswap_ulong(value);
#else
uint32_t Byte0 = value & 0x000000FF;
uint32_t Byte1 = value & 0x0000FF00;
uint32_t Byte2 = value & 0x00FF0000;
uint32_t Byte3 = value & 0xFF000000;
return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
#endif
}
inline uint16_t ByteSwap_16(uint16_t value) {
#if defined(_MSC_VER) && !defined(_DEBUG)
// The DLL version of the runtime lacks these functions (bug!?), but in a
// release build they're replaced with BSWAP instructions anyway.
return _byteswap_ushort(value);
#else
uint16_t Hi = value << 8;
uint16_t Lo = value >> 8;
return Hi | Lo;
#endif
}
inline unsigned short getSwappedBytes(unsigned short C) { return ByteSwap_16(C); }
inline signed short getSwappedBytes( signed short C) { return ByteSwap_16(C); }
inline unsigned int getSwappedBytes(unsigned int C) { return ByteSwap_32(C); }
inline signed int getSwappedBytes( signed int C) { return ByteSwap_32(C); }
template <class FileTy> struct FileMaker {
FileTy &File;
unsigned SI = 1;
unsigned BI = 0;
FileMaker(FileTy &File) : File(File) {}
unsigned addString(std::string S) {
assert(SI + S.size() + 1 <= sizeof(File.Bytes));
std::copy(S.begin(), S.end(), File.Bytes + SI);
auto OldSI = SI;
SI += S.size() + 1;
return OldSI;
}
void addBucket(unsigned Hash, unsigned Key, unsigned Prefix, unsigned Suffix) {
// 9 & 8
assert(!(File.Header.NumBuckets & (File.Header.NumBuckets - 1)));
unsigned I = Hash & (File.Header.NumBuckets - 1);
do {
if (!File.Buckets[I].Key) {
File.Buckets[I].Key = Key;
File.Buckets[I].Prefix = Prefix;
File.Buckets[I].Suffix = Suffix;
++File.Header.NumEntries;
return;
}
++I;
I &= File.Header.NumBuckets - 1;
} while (I != (Hash & (File.Header.NumBuckets - 1)));
}
};
template <unsigned NumBuckets, unsigned NumBytes> struct MapFile {
HMapHeader Header;
HMapBucket Buckets[NumBuckets];
unsigned char Bytes[NumBytes];
void init() {
memset(this, 0, sizeof(MapFile));
Header.Magic = HMAP_HeaderMagicNumber;
Header.Version = HMAP_HeaderVersion;
Header.NumBuckets = NumBuckets;
Header.StringsOffset = sizeof(Header) + sizeof(Buckets);
}
void swapBytes() {
// using llvm::sys::getSwappedBytes;
Header.Magic = getSwappedBytes(Header.Magic);
Header.Version = getSwappedBytes(Header.Version);
Header.NumBuckets = getSwappedBytes(Header.NumBuckets);
Header.StringsOffset = getSwappedBytes(Header.StringsOffset);
}
NSData *getBuffer() const {
const char *c = reinterpret_cast<const char *>(this);
NSData *data = [NSMutableData dataWithBytes:c length:sizeof(MapFile)];
return data;
}
};
void write() {
struct HMapHeader header;
// 2 :几个Bucket
// 150: buffer大小
// 生成的NumBuckets NumBytes
// NumBuckets NumBytes有影响的
// 研究
// 脚本 -》 Cocoapods pub 实际是脚本表现形式之一
// 最大的亮亮点 不是跑通 害怕
// typedef MapFile<8, 750> FileTy;
// typedef MapFile<2, 200> FileTy;
typedef MapFile<8, 750> FileTy;
FileTy File;
File.init();
//OC
FileMaker<FileTy> Maker(File);
// 原理性东西全部走通了
// 1.Bucket
// key
// xcode生成的
// 原理 -》想象原理没有错
// iOS为什么难
// Apple
// hmap -》搜 -〉搜不出来啥
auto a = Maker.addString("TestApp-Swift.h");
// 前半部分
auto b = Maker.addString("/Users/cloud/Documents/iOS/iOS强化班/LoginiOS高级强化班/第十六节课、单元测试与UI测试/TestApp/");
// 后半部分
auto c = Maker.addString("TestApp-Swift.h");
Maker.addBucket(getHash(@"TestApp-Swift.h"), a, b, c);
auto ViewControllera = Maker.addString("ViewController.h");
auto ViewControllerb = Maker.addString("/Users/cloud/Documents/iOS/iOS强化班/LoginiOS高级强化班/第十六节课、单元测试与UI测试/TestApp/TestApp/");
auto ViewControllerc = Maker.addString("ViewController.h");
Maker.addBucket(getHash(@"ViewController.h"), ViewControllera, ViewControllerb, ViewControllerc);
auto Bridginga = Maker.addString("TestApp-Bridging-Header.h");
auto Bridgingb = Maker.addString("/Users/cloud/Documents/iOS/iOS强化班/LoginiOS高级强化班/第十六节课、单元测试与UI测试/TestApp/TestApp/");
auto Bridgingc = Maker.addString("TestApp-Bridging-Header.h");
Maker.addBucket(getHash(@"TestApp-Bridging-Header.h"), Bridginga, Bridgingb, Bridgingc);
auto ScrollViewa = Maker.addString("TestAppTests-Bridging-Header.h");
auto ScrollViewb = Maker.addString("/Users/cloud/Documents/iOS/iOS强化班/LoginiOS高级强化班/第十六节课、单元测试与UI测试/TestApp/TestAppTests/");
auto ScrollViewc = Maker.addString("TestAppTests-Bridging-Header.h");
Maker.addBucket(getHash(@"TestAppTests-Bridging-Header.h"), ScrollViewa, ScrollViewb, ScrollViewc);
NSData *data = File.getBuffer();
[data getBytes:&header length:sizeof(struct HMapHeader)];
[data writeToFile:@"/Users/cloud/Documents/iOS/iOS强化班/LoginiOS高级强化班/第十六节课、单元测试与UI测试/TestApp/TestApp/mm.hmap" atomically:YES];
bool is_swapped = false;
uint32_t (*swap)(uint32_t) = nop_swap;
if (header.Magic == HMAP_HeaderMagicNumber
&& header.Version == HMAP_HeaderVersion) {
is_swapped = false;
} else if (header.Magic == HMAP_SwappedMagic
&& header.Version == HMAP_SwappedVersion) {
is_swapped = true;
swap = actually_swap;
} else {
warn(/*EX_DATAERR,*/ "header lacks HMAP magic");
return;
}
const uint32_t bucket_count = swap(header.NumBuckets);
printf(
"\tHash bucket count: %" PRIu32 "\n"
"\tString table entry count: %" PRIu32 "\n"
"\tMax value length: %" PRIu32 " bytes\n",
bucket_count,
swap(header.NumEntries),
swap(header.MaxValueLength));
const char *raw = (const char *)data.bytes;
const struct HMapBucket *const buckets = (const struct HMapBucket *const)(raw
+ sizeof(struct HMapHeader));
const char *const string_table = (raw
+ sizeof(struct HMapHeader)
+ bucket_count*sizeof(struct HMapBucket));
for (uint32_t i = 0; i < bucket_count; ++i) {
const struct HMapBucket *const bucket = &(buckets[i]);
if (swap(bucket->Key) == HMAP_EmptyBucketKey) { continue; }
// LLVM is careful to sanity-check bucket-count and strlen,
// but we're just going to assume they're all NUL-terminated
// and not maliciously crafted input files.
//
// This is naive, but this is also not exactly "production" code.
const char *key = string_table + swap(bucket->Key);
const char *prefix = string_table + swap(bucket->Prefix);
const char *suffix = string_table + swap(bucket->Suffix);
NSLog(@"\t- Bucket %" PRIu32 ": "
"Key %s -> Prefix %s, Suffix %s\n",
i,
key, prefix, suffix);
}
}
uint32_t
nop_swap(uint32_t u)
{
return u;
}
uint32_t
actually_swap(uint32_t u)
{
uint32_t n = (
((u & 0xFF) << 24)
| ((u & 0xFF00) << 8)
| ((u & 0xFF0000) >> 8)
| ((u & 0xFF000000) >> 24)
);
return n;
}
int
main(int argc, const char *argv[])
{
assert(actually_swap(HMAP_HeaderMagicNumber) == HMAP_SwappedMagic
&& "failed to properly swap things :(");
write();
putchar('\n');
return EXIT_SUCCESS;
}