Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
libcifpp
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
libcifpp
Commits
e450fee0
Commit
e450fee0
authored
Oct 07, 2020
by
Maarten L. Hekkelman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixed processing links
parent
d7c162c7
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
321 additions
and
74 deletions
+321
-74
.gitignore
+2
-0
include/cif++/Cif++.hpp
+57
-33
src/Cif++.cpp
+1
-2
src/CifParser.cpp
+37
-38
test/unit-test.cpp
+224
-1
No files found.
.gitignore
View file @
e450fee0
...
...
@@ -13,3 +13,5 @@ libcif++.la
config.status
config.log
libtool
rsrc/lib-version.txt
version-info*.txt
include/cif++/Cif++.hpp
View file @
e450fee0
...
...
@@ -347,19 +347,27 @@ namespace detail
static
int
compare
(
const
ItemReference
&
ref
,
double
value
,
bool
icase
)
{
int
result
=
0
;
try
const
char
*
s
=
ref
.
c_str
();
if
(
s
==
nullptr
or
*
s
==
0
)
result
=
1
;
else
{
double
v
=
std
::
stod
(
ref
.
c_str
());
if
(
v
<
value
)
result
=
-
1
;
else
if
(
v
>
value
)
try
{
auto
v
=
std
::
strtod
(
s
,
nullptr
);
if
(
v
<
value
)
result
=
-
1
;
else
if
(
v
>
value
)
result
=
1
;
}
catch
(...)
{
if
(
VERBOSE
)
std
::
cerr
<<
"conversion error in compare for '"
<<
ref
.
c_str
()
<<
'\''
<<
std
::
endl
;
result
=
1
;
}
catch
(...)
{
if
(
VERBOSE
)
std
::
cerr
<<
"conversion error in compare for '"
<<
ref
.
c_str
()
<<
'\''
<<
std
::
endl
;
result
=
1
;
}
}
return
result
;
...
...
@@ -380,19 +388,27 @@ namespace detail
static
int
compare
(
const
ItemReference
&
ref
,
unsigned
long
value
,
bool
icase
)
{
int
result
=
0
;
try
const
char
*
s
=
ref
.
c_str
();
if
(
s
==
nullptr
or
*
s
==
0
)
result
=
1
;
else
{
auto
v
=
std
::
stoul
(
ref
.
c_str
());
if
(
v
<
value
)
result
=
-
1
;
else
if
(
v
>
value
)
try
{
auto
v
=
std
::
strtoul
(
s
,
nullptr
,
10
);
if
(
v
<
value
)
result
=
-
1
;
else
if
(
v
>
value
)
result
=
1
;
}
catch
(...)
{
if
(
VERBOSE
)
std
::
cerr
<<
"conversion error in compare for '"
<<
ref
.
c_str
()
<<
'\''
<<
std
::
endl
;
result
=
1
;
}
catch
(...)
{
if
(
VERBOSE
)
std
::
cerr
<<
"conversion error in compare for '"
<<
ref
.
c_str
()
<<
'\''
<<
std
::
endl
;
result
=
1
;
}
}
return
result
;
...
...
@@ -413,19 +429,27 @@ namespace detail
static
int
compare
(
const
ItemReference
&
ref
,
long
value
,
bool
icase
)
{
int
result
=
0
;
try
const
char
*
s
=
ref
.
c_str
();
if
(
s
==
nullptr
or
*
s
==
0
)
result
=
1
;
else
{
auto
v
=
std
::
stol
(
ref
.
c_str
());
if
(
v
<
value
)
result
=
-
1
;
else
if
(
v
>
value
)
try
{
auto
v
=
std
::
strtol
(
s
,
nullptr
,
10
);
if
(
v
<
value
)
result
=
-
1
;
else
if
(
v
>
value
)
result
=
1
;
}
catch
(...)
{
if
(
VERBOSE
)
std
::
cerr
<<
"conversion error in compare for '"
<<
ref
.
c_str
()
<<
'\''
<<
std
::
endl
;
result
=
1
;
}
catch
(...)
{
if
(
VERBOSE
)
std
::
cerr
<<
"conversion error in compare for '"
<<
ref
.
c_str
()
<<
'\''
<<
std
::
endl
;
result
=
1
;
}
}
return
result
;
...
...
src/Cif++.cpp
View file @
e450fee0
...
...
@@ -2524,7 +2524,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
if
(
pk
==
iv
->
mTag
)
{
childTag
=
ck
;
cond
=
std
::
move
(
cond
)
&&
((
Key
(
ck
)
==
oldStrValue
)
or
Key
(
ck
)
==
Empty
())
;
cond
=
std
::
move
(
cond
)
&&
Key
(
ck
)
==
oldStrValue
;
}
else
{
...
...
@@ -2534,7 +2534,6 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
else
cond
=
std
::
move
(
cond
)
&&
((
Key
(
ck
)
==
value
)
or
Key
(
ck
)
==
Empty
());
}
}
if
(
cif
::
VERBOSE
>=
2
)
...
...
src/CifParser.cpp
View file @
e450fee0
...
...
@@ -890,9 +890,14 @@ void DictParser::linkItems()
error
(
"no datablock"
);
auto
&
dict
=
*
mDataBlock
;
std
::
map
<
std
::
tuple
<
std
::
string
,
std
::
string
>
,
size_t
>
linkIndex
;
std
::
map
<
std
::
tuple
<
std
::
string
,
std
::
string
>
,
int
>
linkGroupIds
;
// links are identified by a parent category, a child category and a group ID
using
key_type
=
std
::
tuple
<
std
::
string
,
std
::
string
,
int
>
;
std
::
map
<
key_type
,
size_t
>
linkIndex
;
// Each link group consists of a set of keys
std
::
vector
<
std
::
tuple
<
std
::
vector
<
std
::
string
>
,
std
::
vector
<
std
::
string
>>>
linkKeys
;
auto
addLink
=
[
&
](
size_t
ix
,
const
std
::
string
&
pk
,
const
std
::
string
&
ck
)
...
...
@@ -918,6 +923,32 @@ void DictParser::linkItems()
auto
&
linkedGroupList
=
dict
[
"pdbx_item_linked_group_list"
];
for
(
auto
gl
:
linkedGroupList
)
{
std
::
string
child
,
parent
;
int
link_group_id
;
cif
::
tie
(
child
,
parent
,
link_group_id
)
=
gl
.
get
(
"child_name"
,
"parent_name"
,
"link_group_id"
);
auto
civ
=
mValidator
.
getValidatorForItem
(
child
);
if
(
civ
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
child
+
"' is not specified"
);
auto
piv
=
mValidator
.
getValidatorForItem
(
parent
);
if
(
piv
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
parent
+
"' is not specified"
);
key_type
key
{
piv
->
mCategory
->
mName
,
civ
->
mCategory
->
mName
,
link_group_id
};
if
(
not
linkIndex
.
count
(
key
))
{
linkIndex
[
key
]
=
linkKeys
.
size
();
linkKeys
.
push_back
({});
}
size_t
ix
=
linkIndex
.
at
(
key
);
addLink
(
ix
,
piv
->
mTag
,
civ
->
mTag
);
}
// Only process inline linked items if the linked group list is absent
if
(
linkedGroupList
.
empty
())
{
// for links recorded in categories but not in pdbx_item_linked_group_list
...
...
@@ -934,7 +965,7 @@ void DictParser::linkItems()
if
(
piv
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
parent
+
"' is not specified"
);
auto
key
=
std
::
make_tuple
(
piv
->
mCategory
->
mName
,
civ
->
mCategory
->
mName
)
;
key_type
key
{
piv
->
mCategory
->
mName
,
civ
->
mCategory
->
mName
,
0
}
;
if
(
not
linkIndex
.
count
(
key
))
{
linkIndex
[
key
]
=
linkKeys
.
size
();
...
...
@@ -945,35 +976,6 @@ void DictParser::linkItems()
addLink
(
ix
,
piv
->
mTag
,
civ
->
mTag
);
}
}
else
{
for
(
auto
gl
:
linkedGroupList
)
{
std
::
string
child
,
parent
;
int
link_group_id
;
cif
::
tie
(
child
,
parent
,
link_group_id
)
=
gl
.
get
(
"child_name"
,
"parent_name"
,
"link_group_id"
);
auto
civ
=
mValidator
.
getValidatorForItem
(
child
);
if
(
civ
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
child
+
"' is not specified"
);
auto
piv
=
mValidator
.
getValidatorForItem
(
parent
);
if
(
piv
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
parent
+
"' is not specified"
);
auto
key
=
std
::
make_tuple
(
piv
->
mCategory
->
mName
,
civ
->
mCategory
->
mName
);
if
(
not
linkIndex
.
count
(
key
))
{
linkIndex
[
key
]
=
linkKeys
.
size
();
linkKeys
.
push_back
({});
linkGroupIds
[
key
]
=
link_group_id
;
}
size_t
ix
=
linkIndex
.
at
(
key
);
addLink
(
ix
,
piv
->
mTag
,
civ
->
mTag
);
}
}
auto
&
linkedGroup
=
dict
[
"pdbx_item_linked_group"
];
...
...
@@ -981,15 +983,12 @@ void DictParser::linkItems()
for
(
auto
&
kv
:
linkIndex
)
{
ValidateLink
link
=
{};
std
::
tie
(
link
.
mParentCategory
,
link
.
mChildCategory
)
=
kv
.
first
;
std
::
tie
(
link
.
mParentCategory
,
link
.
mChildCategory
,
link
.
mLinkGroupID
)
=
kv
.
first
;
if
(
linkGroupIds
.
count
(
kv
.
first
))
link
.
mLinkGroupID
=
linkGroupIds
[
kv
.
first
];
std
::
tie
(
link
.
mParentKeys
,
link
.
mChildKeys
)
=
linkKeys
[
kv
.
second
];
// look up the label
for
(
auto
r
:
linkedGroup
.
find
(
cif
::
Key
(
"category_id"
)
==
link
.
mChildCategory
and
cif
::
Key
(
"link_group_id"
)
==
link
.
mLinkGroupID
))
for
(
auto
r
:
linkedGroup
.
find
(
cif
::
Key
(
"category_id"
)
==
link
.
mChildCategory
and
cif
::
Key
(
"link_group_id"
)
==
link
.
mLinkGroupID
))
{
link
.
mLinkGroupLabel
=
r
[
"label"
].
as
<
std
::
string
>
();
break
;
...
...
test/unit-test.cpp
View file @
e450fee0
...
...
@@ -611,7 +611,6 @@ _cat_2.desc
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE
(
d4
)
...
...
@@ -838,3 +837,226 @@ _cat_2.parent_id3
f
.
write
(
std
::
cout
,
{});
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE
(
d5
)
{
const
char
dict
[]
=
R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
;
A test dictionary
;
_dictionary.title test_dict.dic
_dictionary.datablock_id test_dict.dic
_dictionary.version 1.0
loop_
_item_type_list.code
_item_type_list.primitive_code
_item_type_list.construct
code char
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
text char
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
int numb
'[+-]?[0-9]+'
save_cat_1
_category.description 'A simple test category'
_category.id cat_1
_category.mandatory_code no
_category_key.name '_cat_1.id'
save_
save__cat_1.id
_item.name '_cat_1.id'
_item.category_id cat_1
_item.mandatory_code yes
_item_type.code int
save_
save_cat_2
_category.description 'A second simple test category'
_category.id cat_2
_category.mandatory_code no
_category_key.name '_cat_2.id'
save_
save__cat_2.id
_item.name '_cat_2.id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
save__cat_2.parent_id
_item.name '_cat_2.parent_id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
save__cat_2.parent_id2
_item.name '_cat_2.parent_id2'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code code
save_
save__cat_2.parent_id3
_item.name '_cat_2.parent_id3'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code code
save_
loop_
_pdbx_item_linked_group_list.child_category_id
_pdbx_item_linked_group_list.link_group_id
_pdbx_item_linked_group_list.child_name
_pdbx_item_linked_group_list.parent_name
_pdbx_item_linked_group_list.parent_category_id
cat_2 1 '_cat_2.parent_id' '_cat_1.id' cat_1
cat_2 2 '_cat_2.parent_id2' '_cat_1.id' cat_1
cat_2 3 '_cat_2.parent_id3' '_cat_1.id' cat_1
loop_
_pdbx_item_linked_group.category_id
_pdbx_item_linked_group.link_group_id
_pdbx_item_linked_group.label
cat_2 1 cat_2:cat_1:1
cat_2 2 cat_2:cat_1:2
cat_2 3 cat_2:cat_1:3
)"
;
struct
membuf
:
public
std
::
streambuf
{
membuf
(
char
*
text
,
size_t
length
)
{
this
->
setg
(
text
,
text
,
text
+
length
);
}
}
buffer
(
const_cast
<
char
*>
(
dict
),
sizeof
(
dict
)
-
1
);
std
::
istream
is_dict
(
&
buffer
);
cif
::
File
f
;
f
.
loadDictionary
(
is_dict
);
// --------------------------------------------------------------------
const
char
data
[]
=
R"(
data_test
loop_
_cat_1.id
1
2
3
loop_
_cat_2.id
_cat_2.parent_id
_cat_2.parent_id2
_cat_2.parent_id3
1 1 ? ?
2 ? 1 ?
3 ? ? 1
4 2 2 ?
5 2 ? 2
6 ? 2 2
7 3 3 3
)"
;
struct
data_membuf
:
public
std
::
streambuf
{
data_membuf
(
char
*
text
,
size_t
length
)
{
this
->
setg
(
text
,
text
,
text
+
length
);
}
}
data_buffer
(
const_cast
<
char
*>
(
data
),
sizeof
(
data
)
-
1
);
std
::
istream
is_data
(
&
data_buffer
);
f
.
load
(
is_data
);
auto
&
cat1
=
f
.
firstDatablock
()[
"cat_1"
];
auto
&
cat2
=
f
.
firstDatablock
()[
"cat_2"
];
// check a rename in parent and child
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
1
))
{
r
[
"id"
]
=
10
;
break
;
}
f
.
write
(
std
::
cout
,
{});
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
7
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
10
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
10
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
10
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
10
).
size
()
==
1
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
))
{
r
[
"id"
]
=
20
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
7
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
20
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
2
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
2
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
2
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
20
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
20
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
20
).
size
()
==
2
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
3
))
{
r
[
"id"
]
=
30
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
7
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
3
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
30
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
3
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
3
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
3
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
30
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
30
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
30
).
size
()
==
1
);
// test delete
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
10
);
BOOST_CHECK
(
cat1
.
size
()
==
2
);
BOOST_CHECK
(
cat2
.
size
()
==
4
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
20
);
BOOST_CHECK
(
cat1
.
size
()
==
1
);
BOOST_CHECK
(
cat2
.
size
()
==
1
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
30
);
BOOST_CHECK
(
cat1
.
size
()
==
0
);
BOOST_CHECK
(
cat2
.
size
()
==
0
);
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment