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
0f8a7c48
Unverified
Commit
0f8a7c48
authored
Jan 04, 2024
by
Maarten L. Hekkelman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix design flaw in category_index (when moving categories)
parent
47e59a55
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
57 additions
and
58 deletions
+57
-58
changelog
+1
-0
src/category.cpp
+56
-58
No files found.
changelog
View file @
0f8a7c48
...
@@ -4,6 +4,7 @@ Version 6.0.1
...
@@ -4,6 +4,7 @@ Version 6.0.1
-
Change
default
order
to
write
out
categories
in
a
file
based
on
-
Change
default
order
to
write
out
categories
in
a
file
based
on
parent
/
child
relationship
parent
/
child
relationship
-
Added
validate_pdbx
and
recover_pdbx
-
Added
validate_pdbx
and
recover_pdbx
-
Fixed
a
serious
bug
in
category_index
when
moving
categories
Version
6.0.0
Version
6.0.0
-
Drop
the
use
of
CCP4
's monomer library for compound information
-
Drop
the
use
of
CCP4
's monomer library for compound information
...
...
src/category.cpp
View file @
0f8a7c48
...
@@ -47,7 +47,6 @@ class row_comparator
...
@@ -47,7 +47,6 @@ class row_comparator
{
{
public
:
public
:
row_comparator
(
category
&
cat
)
row_comparator
(
category
&
cat
)
:
m_category
(
cat
)
{
{
auto
cv
=
cat
.
get_cat_validator
();
auto
cv
=
cat
.
get_cat_validator
();
...
@@ -69,13 +68,13 @@ class row_comparator
...
@@ -69,13 +68,13 @@ class row_comparator
}
}
}
}
int
operator
()(
const
row
*
a
,
const
row
*
b
)
const
int
operator
()(
const
category
&
cat
,
const
row
*
a
,
const
row
*
b
)
const
{
{
assert
(
a
);
assert
(
a
);
assert
(
b
);
assert
(
b
);
row_handle
rha
(
m_category
,
*
a
);
row_handle
rha
(
cat
,
*
a
);
row_handle
rhb
(
m_category
,
*
b
);
row_handle
rhb
(
cat
,
*
b
);
int
d
=
0
;
int
d
=
0
;
for
(
const
auto
&
[
k
,
f
]
:
m_comparator
)
for
(
const
auto
&
[
k
,
f
]
:
m_comparator
)
...
@@ -92,11 +91,11 @@ class row_comparator
...
@@ -92,11 +91,11 @@ class row_comparator
return
d
;
return
d
;
}
}
int
operator
()(
const
row_initializer
&
a
,
const
row
*
b
)
const
int
operator
()(
const
category
&
cat
,
const
row_initializer
&
a
,
const
row
*
b
)
const
{
{
assert
(
b
);
assert
(
b
);
row_handle
rhb
(
m_category
,
*
b
);
row_handle
rhb
(
cat
,
*
b
);
int
d
=
0
;
int
d
=
0
;
auto
ai
=
a
.
begin
();
auto
ai
=
a
.
begin
();
...
@@ -124,7 +123,6 @@ class row_comparator
...
@@ -124,7 +123,6 @@ class row_comparator
using
key_comparator
=
std
::
tuple
<
uint16_t
,
compareFunc
>
;
using
key_comparator
=
std
::
tuple
<
uint16_t
,
compareFunc
>
;
std
::
vector
<
key_comparator
>
m_comparator
;
std
::
vector
<
key_comparator
>
m_comparator
;
category
&
m_category
;
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -135,18 +133,18 @@ class row_comparator
...
@@ -135,18 +133,18 @@ class row_comparator
class
category_index
class
category_index
{
{
public
:
public
:
category_index
(
category
*
cat
);
category_index
(
category
&
cat
);
~
category_index
()
~
category_index
()
{
{
delete
m_root
;
delete
m_root
;
}
}
row
*
find
(
row
*
k
)
const
;
row
*
find
(
const
category
&
cat
,
row
*
k
)
const
;
row
*
find_by_value
(
row_initializer
k
)
const
;
row
*
find_by_value
(
const
category
&
cat
,
row_initializer
k
)
const
;
void
insert
(
row
*
r
);
void
insert
(
category
&
cat
,
row
*
r
);
void
erase
(
row
*
r
);
void
erase
(
category
&
cat
,
row
*
r
);
// reorder the row's and returns new head and tail
// reorder the row's and returns new head and tail
std
::
tuple
<
row
*
,
row
*>
reorder
()
std
::
tuple
<
row
*
,
row
*>
reorder
()
...
@@ -192,8 +190,8 @@ class category_index
...
@@ -192,8 +190,8 @@ class category_index
bool
m_red
;
bool
m_red
;
};
};
entry
*
insert
(
entry
*
h
,
row
*
v
);
entry
*
insert
(
category
&
cat
,
entry
*
h
,
row
*
v
);
entry
*
erase
(
entry
*
h
,
row
*
k
);
entry
*
erase
(
category
&
cat
,
entry
*
h
,
row
*
k
);
// void validate(entry* h, bool isParentRed, uint32_t blackDepth, uint32_t& minBlack, uint32_t& maxBlack) const;
// void validate(entry* h, bool isParentRed, uint32_t blackDepth, uint32_t& minBlack, uint32_t& maxBlack) const;
...
@@ -324,26 +322,24 @@ class category_index
...
@@ -324,26 +322,24 @@ class category_index
return
result
;
return
result
;
}
}
category
&
m_category
;
row_comparator
m_row_comparator
;
row_comparator
m_row_comparator
;
entry
*
m_root
;
entry
*
m_root
;
};
};
category_index
::
category_index
(
category
*
cat
)
category_index
::
category_index
(
category
&
cat
)
:
m_category
(
*
cat
)
:
m_row_comparator
(
cat
)
,
m_row_comparator
(
m_category
)
,
m_root
(
nullptr
)
,
m_root
(
nullptr
)
{
{
for
(
auto
r
:
m_category
)
for
(
auto
r
:
cat
)
insert
(
r
.
get_row
());
insert
(
cat
,
r
.
get_row
());
}
}
row
*
category_index
::
find
(
row
*
k
)
const
row
*
category_index
::
find
(
const
category
&
cat
,
row
*
k
)
const
{
{
const
entry
*
r
=
m_root
;
const
entry
*
r
=
m_root
;
while
(
r
!=
nullptr
)
while
(
r
!=
nullptr
)
{
{
int
d
=
m_row_comparator
(
k
,
r
->
m_row
);
int
d
=
m_row_comparator
(
cat
,
k
,
r
->
m_row
);
if
(
d
<
0
)
if
(
d
<
0
)
r
=
r
->
m_left
;
r
=
r
->
m_left
;
else
if
(
d
>
0
)
else
if
(
d
>
0
)
...
@@ -355,14 +351,14 @@ row *category_index::find(row *k) const
...
@@ -355,14 +351,14 @@ row *category_index::find(row *k) const
return
r
?
r
->
m_row
:
nullptr
;
return
r
?
r
->
m_row
:
nullptr
;
}
}
row
*
category_index
::
find_by_value
(
row_initializer
k
)
const
row
*
category_index
::
find_by_value
(
const
category
&
cat
,
row_initializer
k
)
const
{
{
// sort the values in k first
// sort the values in k first
row_initializer
k2
;
row_initializer
k2
;
for
(
auto
&
f
:
m_category
.
key_field_indices
())
for
(
auto
&
f
:
cat
.
key_field_indices
())
{
{
auto
fld
=
m_category
.
get_column_name
(
f
);
auto
fld
=
cat
.
get_column_name
(
f
);
auto
ki
=
find_if
(
k
.
begin
(),
k
.
end
(),
[
&
fld
](
auto
&
i
)
{
return
i
.
name
()
==
fld
;
});
auto
ki
=
find_if
(
k
.
begin
(),
k
.
end
(),
[
&
fld
](
auto
&
i
)
{
return
i
.
name
()
==
fld
;
});
if
(
ki
==
k
.
end
())
if
(
ki
==
k
.
end
())
...
@@ -374,7 +370,7 @@ row *category_index::find_by_value(row_initializer k) const
...
@@ -374,7 +370,7 @@ row *category_index::find_by_value(row_initializer k) const
const
entry
*
r
=
m_root
;
const
entry
*
r
=
m_root
;
while
(
r
!=
nullptr
)
while
(
r
!=
nullptr
)
{
{
int
d
=
m_row_comparator
(
k2
,
r
->
m_row
);
int
d
=
m_row_comparator
(
cat
,
k2
,
r
->
m_row
);
if
(
d
<
0
)
if
(
d
<
0
)
r
=
r
->
m_left
;
r
=
r
->
m_left
;
else
if
(
d
>
0
)
else
if
(
d
>
0
)
...
@@ -386,34 +382,34 @@ row *category_index::find_by_value(row_initializer k) const
...
@@ -386,34 +382,34 @@ row *category_index::find_by_value(row_initializer k) const
return
r
?
r
->
m_row
:
nullptr
;
return
r
?
r
->
m_row
:
nullptr
;
}
}
void
category_index
::
insert
(
row
*
k
)
void
category_index
::
insert
(
category
&
cat
,
row
*
k
)
{
{
m_root
=
insert
(
m_root
,
k
);
m_root
=
insert
(
cat
,
m_root
,
k
);
m_root
->
m_red
=
false
;
m_root
->
m_red
=
false
;
}
}
category_index
::
entry
*
category_index
::
insert
(
entry
*
h
,
row
*
v
)
category_index
::
entry
*
category_index
::
insert
(
category
&
cat
,
entry
*
h
,
row
*
v
)
{
{
if
(
h
==
nullptr
)
if
(
h
==
nullptr
)
return
new
entry
(
v
);
return
new
entry
(
v
);
int
d
=
m_row_comparator
(
v
,
h
->
m_row
);
int
d
=
m_row_comparator
(
cat
,
v
,
h
->
m_row
);
if
(
d
<
0
)
if
(
d
<
0
)
h
->
m_left
=
insert
(
h
->
m_left
,
v
);
h
->
m_left
=
insert
(
cat
,
h
->
m_left
,
v
);
else
if
(
d
>
0
)
else
if
(
d
>
0
)
h
->
m_right
=
insert
(
h
->
m_right
,
v
);
h
->
m_right
=
insert
(
cat
,
h
->
m_right
,
v
);
else
else
{
{
row_handle
rh
(
m_category
,
*
v
);
row_handle
rh
(
cat
,
*
v
);
std
::
ostringstream
os
;
std
::
ostringstream
os
;
for
(
auto
col
:
m_category
.
key_fields
())
for
(
auto
col
:
cat
.
key_fields
())
{
{
if
(
rh
[
col
])
if
(
rh
[
col
])
os
<<
col
<<
": "
<<
std
::
quoted
(
rh
[
col
].
text
())
<<
"; "
;
os
<<
col
<<
": "
<<
std
::
quoted
(
rh
[
col
].
text
())
<<
"; "
;
}
}
throw
duplicate_key_error
(
"Duplicate Key violation, cat: "
+
m_category
.
name
()
+
" values: "
+
os
.
str
());
throw
duplicate_key_error
(
"Duplicate Key violation, cat: "
+
cat
.
name
()
+
" values: "
+
os
.
str
());
}
}
if
(
is_red
(
h
->
m_right
)
and
not
is_red
(
h
->
m_left
))
if
(
is_red
(
h
->
m_right
)
and
not
is_red
(
h
->
m_left
))
...
@@ -428,25 +424,25 @@ category_index::entry *category_index::insert(entry *h, row *v)
...
@@ -428,25 +424,25 @@ category_index::entry *category_index::insert(entry *h, row *v)
return
h
;
return
h
;
}
}
void
category_index
::
erase
(
row
*
k
)
void
category_index
::
erase
(
category
&
cat
,
row
*
k
)
{
{
assert
(
find
(
k
)
==
k
);
assert
(
find
(
cat
,
k
)
==
k
);
m_root
=
erase
(
m_root
,
k
);
m_root
=
erase
(
cat
,
m_root
,
k
);
if
(
m_root
!=
nullptr
)
if
(
m_root
!=
nullptr
)
m_root
->
m_red
=
false
;
m_root
->
m_red
=
false
;
}
}
category_index
::
entry
*
category_index
::
erase
(
entry
*
h
,
row
*
k
)
category_index
::
entry
*
category_index
::
erase
(
category
&
cat
,
entry
*
h
,
row
*
k
)
{
{
if
(
m_row_comparator
(
k
,
h
->
m_row
)
<
0
)
if
(
m_row_comparator
(
cat
,
k
,
h
->
m_row
)
<
0
)
{
{
if
(
h
->
m_left
!=
nullptr
)
if
(
h
->
m_left
!=
nullptr
)
{
{
if
(
not
is_red
(
h
->
m_left
)
and
not
is_red
(
h
->
m_left
->
m_left
))
if
(
not
is_red
(
h
->
m_left
)
and
not
is_red
(
h
->
m_left
->
m_left
))
h
=
move_red_left
(
h
);
h
=
move_red_left
(
h
);
h
->
m_left
=
erase
(
h
->
m_left
,
k
);
h
->
m_left
=
erase
(
cat
,
h
->
m_left
,
k
);
}
}
}
}
else
else
...
@@ -454,7 +450,7 @@ category_index::entry *category_index::erase(entry *h, row *k)
...
@@ -454,7 +450,7 @@ category_index::entry *category_index::erase(entry *h, row *k)
if
(
is_red
(
h
->
m_left
))
if
(
is_red
(
h
->
m_left
))
h
=
rotateRight
(
h
);
h
=
rotateRight
(
h
);
if
(
m_row_comparator
(
k
,
h
->
m_row
)
==
0
and
h
->
m_right
==
nullptr
)
if
(
m_row_comparator
(
cat
,
k
,
h
->
m_row
)
==
0
and
h
->
m_right
==
nullptr
)
{
{
delete
h
;
delete
h
;
return
nullptr
;
return
nullptr
;
...
@@ -465,13 +461,13 @@ category_index::entry *category_index::erase(entry *h, row *k)
...
@@ -465,13 +461,13 @@ category_index::entry *category_index::erase(entry *h, row *k)
if
(
not
is_red
(
h
->
m_right
)
and
not
is_red
(
h
->
m_right
->
m_left
))
if
(
not
is_red
(
h
->
m_right
)
and
not
is_red
(
h
->
m_right
->
m_left
))
h
=
move_red_right
(
h
);
h
=
move_red_right
(
h
);
if
(
m_row_comparator
(
k
,
h
->
m_row
)
==
0
)
if
(
m_row_comparator
(
cat
,
k
,
h
->
m_row
)
==
0
)
{
{
h
->
m_row
=
find_min
(
h
->
m_right
)
->
m_row
;
h
->
m_row
=
find_min
(
h
->
m_right
)
->
m_row
;
h
->
m_right
=
erase_min
(
h
->
m_right
);
h
->
m_right
=
erase_min
(
h
->
m_right
);
}
}
else
else
h
->
m_right
=
erase
(
h
->
m_right
,
k
);
h
->
m_right
=
erase
(
cat
,
h
->
m_right
,
k
);
}
}
}
}
...
@@ -520,7 +516,7 @@ category::category(const category &rhs)
...
@@ -520,7 +516,7 @@ category::category(const category &rhs)
insert_impl
(
end
(),
clone_row
(
*
r
));
insert_impl
(
end
(),
clone_row
(
*
r
));
if
(
m_cat_validator
!=
nullptr
and
m_index
==
nullptr
)
if
(
m_cat_validator
!=
nullptr
and
m_index
==
nullptr
)
m_index
=
new
category_index
(
this
);
m_index
=
new
category_index
(
*
this
);
}
}
category
::
category
(
category
&&
rhs
)
category
::
category
(
category
&&
rhs
)
...
@@ -564,7 +560,7 @@ category &category::operator=(const category &rhs)
...
@@ -564,7 +560,7 @@ category &category::operator=(const category &rhs)
m_cat_validator
=
rhs
.
m_cat_validator
;
m_cat_validator
=
rhs
.
m_cat_validator
;
if
(
m_cat_validator
!=
nullptr
and
m_index
==
nullptr
)
if
(
m_cat_validator
!=
nullptr
and
m_index
==
nullptr
)
m_index
=
new
category_index
(
this
);
m_index
=
new
category_index
(
*
this
);
}
}
return
*
this
;
return
*
this
;
...
@@ -669,7 +665,7 @@ void category::set_validator(const validator *v, datablock &db)
...
@@ -669,7 +665,7 @@ void category::set_validator(const validator *v, datablock &db)
}
}
if
(
missing
.
empty
())
if
(
missing
.
empty
())
m_index
=
new
category_index
(
this
);
m_index
=
new
category_index
(
*
this
);
else
else
{
{
std
::
ostringstream
msg
;
std
::
ostringstream
msg
;
...
@@ -782,7 +778,7 @@ bool category::is_valid() const
...
@@ -782,7 +778,7 @@ bool category::is_valid() const
for
(
auto
r
:
*
this
)
for
(
auto
r
:
*
this
)
{
{
auto
p
=
r
.
get_row
();
auto
p
=
r
.
get_row
();
if
(
m_index
->
find
(
p
)
!=
p
)
if
(
m_index
->
find
(
*
this
,
p
)
!=
p
)
m_validator
->
report_error
(
"Key not found in index for category "
+
m_name
,
true
);
m_validator
->
report_error
(
"Key not found in index for category "
+
m_name
,
true
);
}
}
}
}
...
@@ -904,7 +900,7 @@ row_handle category::operator[](const key_type &key)
...
@@ -904,7 +900,7 @@ row_handle category::operator[](const key_type &key)
if
(
m_index
==
nullptr
)
if
(
m_index
==
nullptr
)
throw
std
::
logic_error
(
"Category "
+
m_name
+
" does not have an index"
);
throw
std
::
logic_error
(
"Category "
+
m_name
+
" does not have an index"
);
auto
row
=
m_index
->
find_by_value
(
key
);
auto
row
=
m_index
->
find_by_value
(
*
this
,
key
);
if
(
row
!=
nullptr
)
if
(
row
!=
nullptr
)
result
=
{
*
this
,
*
row
};
result
=
{
*
this
,
*
row
};
}
}
...
@@ -1078,7 +1074,7 @@ category::iterator category::erase(iterator pos)
...
@@ -1078,7 +1074,7 @@ category::iterator category::erase(iterator pos)
throw
std
::
runtime_error
(
"erase"
);
throw
std
::
runtime_error
(
"erase"
);
if
(
m_index
!=
nullptr
)
if
(
m_index
!=
nullptr
)
m_index
->
erase
(
r
);
m_index
->
erase
(
*
this
,
r
);
if
(
r
==
m_head
)
if
(
r
==
m_head
)
{
{
...
@@ -1250,12 +1246,14 @@ std::string category::get_unique_id(std::function<std::string(int)> generator)
...
@@ -1250,12 +1246,14 @@ std::string category::get_unique_id(std::function<std::string(int)> generator)
std
::
string
id_tag
=
"id"
;
std
::
string
id_tag
=
"id"
;
if
(
m_cat_validator
!=
nullptr
and
m_cat_validator
->
m_keys
.
size
()
==
1
)
if
(
m_cat_validator
!=
nullptr
and
m_cat_validator
->
m_keys
.
size
()
==
1
)
{
{
id_tag
=
m_cat_validator
->
m_keys
.
front
();
if
(
m_index
==
nullptr
and
m_cat_validator
!=
nullptr
)
if
(
m_index
==
nullptr
and
m_cat_validator
!=
nullptr
)
m_index
=
new
category_index
(
this
);
m_index
=
new
category_index
(
*
this
);
for
(;;)
for
(;;)
{
{
if
(
m_index
->
find_by_value
({{
id_tag
,
result
}})
==
nullptr
)
if
(
m_index
->
find_by_value
(
*
this
,
{{
id_tag
,
result
}})
==
nullptr
)
break
;
break
;
result
=
generator
(
static_cast
<
int
>
(
m_last_unique_num
++
));
result
=
generator
(
static_cast
<
int
>
(
m_last_unique_num
++
));
}
}
...
@@ -1407,7 +1405,7 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
...
@@ -1407,7 +1405,7 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
{
{
// make sure we have an index, if possible
// make sure we have an index, if possible
if
(
m_index
==
nullptr
and
m_cat_validator
!=
nullptr
)
if
(
m_index
==
nullptr
and
m_cat_validator
!=
nullptr
)
m_index
=
new
category_index
(
this
);
m_index
=
new
category_index
(
*
this
);
auto
&
col
=
m_columns
[
column
];
auto
&
col
=
m_columns
[
column
];
...
@@ -1433,9 +1431,9 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
...
@@ -1433,9 +1431,9 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
if
(
updateLinked
and
// an update of an Item's value
if
(
updateLinked
and
// an update of an Item's value
m_index
!=
nullptr
and
key_field_indices
().
count
(
column
))
m_index
!=
nullptr
and
key_field_indices
().
count
(
column
))
{
{
reinsert
=
m_index
->
find
(
row
);
reinsert
=
m_index
->
find
(
*
this
,
row
);
if
(
reinsert
)
if
(
reinsert
)
m_index
->
erase
(
row
);
m_index
->
erase
(
*
this
,
row
);
}
}
// first remove old value with cix
// first remove old value with cix
...
@@ -1446,7 +1444,7 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
...
@@ -1446,7 +1444,7 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
row
->
append
(
column
,
{
value
});
row
->
append
(
column
,
{
value
});
if
(
reinsert
)
if
(
reinsert
)
m_index
->
insert
(
row
);
m_index
->
insert
(
*
this
,
row
);
// see if we need to update any child categories that depend on this value
// see if we need to update any child categories that depend on this value
auto
iv
=
col
.
m_validator
;
auto
iv
=
col
.
m_validator
;
...
@@ -1602,7 +1600,7 @@ row_handle category::create_copy(row_handle r)
...
@@ -1602,7 +1600,7 @@ row_handle category::create_copy(row_handle r)
category
::
iterator
category
::
insert_impl
(
const_iterator
pos
,
row
*
n
)
category
::
iterator
category
::
insert_impl
(
const_iterator
pos
,
row
*
n
)
{
{
if
(
m_index
==
nullptr
and
m_cat_validator
!=
nullptr
)
if
(
m_index
==
nullptr
and
m_cat_validator
!=
nullptr
)
m_index
=
new
category_index
(
this
);
m_index
=
new
category_index
(
*
this
);
assert
(
n
!=
nullptr
);
assert
(
n
!=
nullptr
);
assert
(
n
->
m_next
==
nullptr
);
assert
(
n
->
m_next
==
nullptr
);
...
@@ -1642,7 +1640,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
...
@@ -1642,7 +1640,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
}
}
if
(
m_index
!=
nullptr
)
if
(
m_index
!=
nullptr
)
m_index
->
insert
(
n
);
m_index
->
insert
(
*
this
,
n
);
// insert at end, most often this is the case
// insert at end, most often this is the case
if
(
pos
.
m_current
==
nullptr
)
if
(
pos
.
m_current
==
nullptr
)
...
...
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