1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
/*
* Copyright (c) Schrodinger, LLC.
*
* Datastructure for `bond_dict`, parsed from CIF files with
* `chem_comp_bond` records.
*
* This file includes a generic reference implementation (1), and an
* optimized fast and memory efficient implementation (2) with key
* string length limitations.
*/
#ifndef CIFBONDDICT_H
#define CIFBONDDICT_H
#include <map>
#include <algorithm>
#include <string>
#include "os_std.h"
#include "PyMOLGlobals.h"
#if 1
// (2)
// Optimized implementation, tuned on speed and memory usage.
// Only supports resn length <= 8 and atom name length <= 4.
// Working with this limitation is currently reasonable in PyMOL,
// since cResnLen=5 and cAtomNameLen=4 (see AtomInfo.h).
#include <cstdint>
#include <unordered_map>
#include <string.h>
// mapped type of bond_dict_t
class res_bond_dict_t {
using key_type = std::int_fast64_t;
using halfkey_t = std::int32_t;
using mapped_type = signed char;
static halfkey_t make_halfkey(const char* name) {
union { halfkey_t i; char s[sizeof(halfkey_t)]; };
strncpy(s, name, sizeof(halfkey_t));
return i;
}
static key_type make_key(const char * name1, const char * name2) {
auto i1 = make_halfkey(name1);
auto i2 = make_halfkey(name2);
if (i1 > i2)
std::swap(i1, i2);
// construct 8-byte key from the two 4-byte names
return (((key_type)i1) << 32) | i2;
}
std::unordered_map<key_type, mapped_type> m_map;
std::unordered_map<halfkey_t, std::string> m_alt_names;
const char* get_standard_name(const char* name) const {
auto it = m_alt_names.find(make_halfkey(name));
if (it != m_alt_names.end()) {
return it->second.c_str();
}
return name;
}
public:
void add_alt_name(const char* name, const char* alt) {
m_alt_names[make_halfkey(alt)] = name;
}
void set(const char * name1, const char * name2, mapped_type order) {
m_map[make_key(name1, name2)] = order;
}
mapped_type get(const char * name1, const char * name2) const {
name1 = get_standard_name(name1);
name2 = get_standard_name(name2);
auto it = m_map.find(make_key(name1, name2));
if (it == m_map.end())
return -1;
return it->second;
}
};
// type for mapping: resn -> ((name1, name2) -> bond order)
class bond_dict_t {
using key_type = std::int_fast64_t;
using mapped_type = res_bond_dict_t;
static key_type make_key(const char * s_) {
union { key_type i; char s[sizeof(key_type)]; };
strncpy(s, s_, sizeof(s));
return i;
}
std::map<key_type, mapped_type> m_map;
std::set<key_type> unknown_resn;
public:
bool empty() const { return m_map.empty(); }
mapped_type& operator[](const char* resn) { return m_map[make_key(resn)]; }
void set_unknown(const char * resn) {
unknown_resn.insert(make_key(resn));
}
const mapped_type * get(PyMOLGlobals *, const char * resn, bool try_download=true);
};
#else
// (1)
// Generic reference implementation. Supports arbitrary key lengths,
// but is slower and less memory efficient. Equivalent to:
//
// typedef std::map<std::string,
// std::map<std::string,
// std::map<std::string, int> > > bond_dict_t;
//
// with added get/set methods.
#include <string>
class res_bond_dict_t {
std::map<std::string, std::map<std::string, int> > m_data;
public:
void set(const char * name1, const char * name2, int order) {
if (strcmp(name1, name2) < 0)
std::swap(name1, name2);
m_data[name1][name2] = order;
}
int get(const char * name1, const char * name2) const {
if (strcmp(name1, name2) < 0)
std::swap(name1, name2);
try {
return m_data.at(name1).at(name2);
} catch (const std::out_of_range& e) {
return -1;
}
}
};
class bond_dict_t {
std::map<std::string, res_bond_dict_t> m_data;
public:
void set(const char * resn, const char * name1, const char * name2, int order) {
m_data[resn].set(name1, name2, order);
}
const res_bond_dict_t * get(const char * resn) const {
auto it = m_data.find(resn);
if (it == m_data.end())
return NULL;
return &it->second;
}
bool empty() const {
return m_data.empty();
}
};
#endif
#endif
|